Skip to content

Instantly share code, notes, and snippets.

@diyinfosec
Created May 28, 2022 16:03
Show Gist options
  • Save diyinfosec/e33709d0cc9321822d2038fa260c3374 to your computer and use it in GitHub Desktop.
Save diyinfosec/e33709d0cc9321822d2038fa260c3374 to your computer and use it in GitHub Desktop.
#!/bin/bash
#- Script to setup Docker, Minikube, Kubectl, Helm on Ubuntu.
#- On the K8s cluster install - Vault, Consul, Datadog agent.
#- Access to K8s dashboard is provided through nginx on port 5000. http://<host_ip>:5000
#- Acess to Vault UI is provided through kubectl port-forward. http://<host_ip>:8200
#- I use multipass for the VMs, so rebuild a VM the following steps are applicable.
#- For the first time, the first two commands can be ignored.
# multipass delete ktest
# multipass purge
# multipass launch -n ktest -m 4G -d 20G -c 2
# multipass transfer ./manage.sh ktest:/home/ubuntu/manage.sh
# multipass exec ktest -- chmod +x /home/ubuntu/manage.sh
# multipass exec ktest -- /home/ubuntu/manage.sh -t auto
# multipass shell ktest
#===================================================================
#- Runs a command and returns true/false based on exec status.
#===================================================================
function check_install()
{
$1 > /dev/null 2>&1
status=$?
#echo "status is "$status
if test $status -eq 0
then
true
else
false
fi
}
#===================================================================
#- Check if the current user can sudo, else exit
#===================================================================
function check_sudo()
{
if ! check_install 'sudo touch /dev/null'
then
echo "User "$USER "cannot run sudo. Exiting..."
exit 1
fi
}
#===================================================================
#- Setup some useful aliases in bashrc
#===================================================================
function setup_aliases()
{
#- Basic aliases
tee -a $HOME/.bashrc <<EOF
alias rc='source ~/.bashrc'
alias l='ls -rlat'
alias m='$HOME/manage.sh -t menu'
alias c='clear'
alias k='kubectl'
alias kl='kubectl logs kube-apiserver-minikube -n kube-system | grep audit.k8s.io/v1'
sudo chown $USER /var/run/docker.sock
function dds()
{
echo "This function prints the status of the Datadog agent"
sleep 2;
export AGENT_POD=\$(kubectl get pods -l app.kubernetes.io/component=agent,app=datadog-agent -o name);
echo \$AGENT_POD
if test "x"\$AGENT_POD != "x"
then
kubectl exec -it \$AGENT_POD -c agent -- agent status;
else
echo "Datadog agent pod is not running."
fi
}
EOF
. $HOME/.bashrc
}
#===================================================================
#- Install docker, conntrack, jq, net-tools
#===================================================================
function install_basics()
{
#- Installing docker
if ! check_install 'docker --version'
then
echo "Installing docker"
curl -fsSL https://get.docker.com | bash
#- Permissions for docker.sock
#- You can also do, sudo chmod 666 /var/run/docker.sock but it stays only till restart!
#- Ref: https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user
echo "Fixing the docker permissions"
#trap 'sudo groupadd docker' EXIT
#trap 'sudo usermod -aG docker $USER' EXIT
sudo gpasswd -a $USER docker
echo 'User:'$USER 'is member of '$(groups $USER)
#sleep 5
#- Login to the docker group
#newgrp docker
#trap 'sudo systemctl restart docker' EXIT
#- Final solution I came up with was to change ownership of docker.sock to Ubuntu. Add this line to .bashrc
sudo chown $USER /var/run/docker.sock
else
echo "Docker is already installed"
fi
#- Installing jq and net-tools
if ! check_install 'jq --version'
then
echo "Installing jq"
sudo -E sh -c 'DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends jq > /dev/null'
else
echo "jq is already installed"
fi
if ! check_install 'netstat -V'
then
echo "Installing net-tools"
sudo -E sh -c 'DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends net-tools > /dev/null'
else
echo "net-tools is already installed"
fi
}
#========================================================================
#- Install minikube
#- Ref: https://minikube.sigs.k8s.io/docs/start/
#- Install kubectl
#- Ref: https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/
#========================================================================
function install_kube_stuff()
{
#- Install conntrack (dependency for minikube)
if ! check_install 'conntrack --version'
then
echo "Installing conntrack"
sudo -E sh -c 'DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends conntrack > /dev/null'
else
echo "conntrack is already installed"
fi
#- Install minikube
if ! check_install 'minikube version'
then
echo "Downloading and installing minikube"
curl -sLO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
else
echo "minikube is already installed"
fi
#- Install kubectl
if ! check_install 'kubectl version'
then
echo "Installing kubectl"
curl -sLO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
curl -sLO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
else
echo "kubectl is already installed"
fi
#- Install helm
if ! check_install 'helm version'
then
echo "Installing helm with snap"
sudo snap install helm --classic
else
echo "helm is already installed"
fi
}
#===================================================================
#- Install nginx - for port forwarding (minikube dashboard)
#- Ref: https://www.hostinger.com/tutorials/how-to-set-up-nginx-reverse-proxy/
#===================================================================
function install_nginx()
{
if check_install 'nginx -v'
then
echo "nginx is already installed"
return
fi
echo "Installing nginx"
sudo apt-get update -qq > /dev/null
sudo apt-get -y install nginx -qq > /dev/null
#- Clean up from previous installs.
echo "Attempting clean-up of conf files"
sudo unlink /etc/nginx/sites-enabled/default 2>/dev/null
sudo rm /etc/nginx/sites-enabled/k8s-dashboard-proxy.conf 2>/dev/null
sudo rm /etc/nginx/sites-available/k8s-dashboard-proxy.conf 2>/dev/null
echo "Creating proxy config for K8s dashboard"
sudo tee /etc/nginx/sites-available/k8s-dashboard-proxy.conf <<EOF
server {
listen 5000;
location / {
proxy_pass http://127.0.0.1:5001/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/;
}
}
EOF
echo "Linking config to sites-enabled"
sudo ln -s /etc/nginx/sites-available/k8s-dashboard-proxy.conf /etc/nginx/sites-enabled/k8s-dashboard-proxy.conf
echo "Restarting nginx"
sudo nginx -t
sudo service nginx restart
}
#=======================================================
#- Audit policy for minikube and start it
#- https://minikube.sigs.k8s.io/docs/tutorials/audit-policy/
#=======================================================
function minikube_start_audit()
{
echo "Creating directory for minikube audit config"
mkdir -p ~/.minikube/files/etc/ssl/certs
echo "Downloading config from Gist"
sudo curl -s https://gist.githubusercontent.com/diyinfosec/7acadaea47a71c82b68f06e13213dd1d/raw/fc02e5823628dd5e9fe794daf84193ee2cb00cb9/k8s-audit-policy.yaml -o ~/.minikube/files/etc/ssl/certs/audit-policy.yaml
#- Looks like we can start minikube over and over, without having to verify if it's running.
echo "Starting minikube with audit enabled"
#- For log rotation, ref: https://sudo-bmitch.github.io/presentations/dc2019/tips-and-tricks-of-the-captains.html#17
minikube start \
--docker-opt=log-driver=json-file --docker-opt=log-opt=max-size=10M --docker-opt=log-opt=max-file=3 \
--extra-config=apiserver.audit-policy-file=/etc/ssl/certs/audit-policy.yaml \
--extra-config=apiserver.audit-log-path=-
status=$?
echo "Minikube command status is "$status
if test $status -ne 0
then
echo "minikube did not start. Aborting installation"
exit 1;
fi
}
#===================================================================
#- Bring up kubernetes dashboard on port 5000
#===================================================================
function minikube_start_dashboard()
{
DASHBOARD_STATUS=$(sudo netstat -tlnp | grep ":5001" | awk '{print $NF}')
if test "x"$DASHBOARD_STATUS != "x"
then
echo "Dashboard seems to be running already. "$DASHBOARD_STATUS
killpid=$(echo $DASHBOARD_STATUS | cut -f1 -d"/")
echo "PID to kill is " $killpid
sudo kill $killpid
minikube_start_dashboard
else
echo "Enabling kubernetes dashboard on port 5001"
nohup minikube dashboard --port=5001 --url=false &
sudo systemctl restart nginx
fi
}
#===================================================================
#- Minikube clear audit log
#===================================================================
function minikube_clear_audit()
{
sudo tee clear_k8s_audit.sh <<EOF
#- Get the name of the api server container
export CONTAINER_NAME=\$(docker ps --filter "name=k8s_kube-apiserver" --format '{{.Names}}')
#- Clear the log file
echo ""> \$(docker inspect --format='{{.LogPath}}' \$CONTAINER_NAME)
EOF
minikube cp clear_k8s_audit.sh /tmp/1.sh
minikube ssh -- /bin/sh sudo /tmp/1.sh
}
#===================================================================
#- Install Consul and Vault using helm
#- Ref: https://learn.hashicorp.com/tutorials/vault/kubernetes-minikube-consul?in=vault/kubernetes
#===================================================================
function install_vault_consul()
{
if check_install 'helm status vault' && check_install 'helm status consul'
then
echo "Vault and Consul are already installed"
return;
fi
tee $HOME/helm-consul-values.yml <<EOF
global:
datacenter: vault-kubernetes-tutorial
client:
enabled: true
server:
replicas: 1
bootstrapExpect: 1
disruptionBudget:
maxUnavailable: 0
EOF
helm repo add hashicorp https://helm.releases.hashicorp.com 2>/dev/null
helm repo update
helm install consul hashicorp/consul --values ./helm-consul-values.yml
#- Values given in: https://github.com/hashicorp/vault-helm/blob/main/values.yaml
#- Theoretically we can enable audit logging here but if I do it then the vault-0 pod doesn't spin up. So I am doing it separately, after this pod has been created
helm install vault hashicorp/vault \
--set server.dev.enabled='true' \
--set ui.enabled='true'
}
#===================================================================
#- Install Consul and Vault using helm
#- Ref: https://learn.hashicorp.com/tutorials/vault/kubernetes-minikube-consul?in=vault/kubernetes
#===================================================================
function remove_vault_consul()
{
read -p "Are you sure you want to continue? <y/N> " prompt
if [[ $prompt =~ [yY](es)* ]]
then
helm uninstall vault
helm uninstall consul
fi
}
#===================================================================
#- Vault - enable k8s auth
#===================================================================
function vault_enable_k8s_auth()
{
tee $HOME/vault_k8s_auth.sh <<FOF
#- Commented because dev server does not need tokens for CLI
# vault login $VAULT_TOKEN
vault auth enable kubernetes
vault write auth/kubernetes/config \\
kubernetes_host="https://\$KUBERNETES_PORT_443_TCP_ADDR:443"
vault policy write webapp - <<EOF
path "secret/data/webapp/config" {
capabilities = ["read"]
}
EOF
vault write auth/kubernetes/role/webapp \\
bound_service_account_names=vault \\
bound_service_account_namespaces=default \\
policies=webapp \\
ttl=24h
exit
FOF
kubectl cp vault_k8s_auth.sh default/vault-0:/tmp/
kubectl exec --stdin=true --tty=true vault-0 -- /bin/sh /tmp/vault_k8s_auth.sh
}
#===================================================================
#- Vault - enable audit logging
#- https://www.vaultproject.io/docs/audit/file#examples
#===================================================================
function vault_enable_audit_logs()
{
while [[ $(kubectl get pods -l app.kubernetes.io/instance=vault,app.kubernetes.io/name=vault,component=server -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}') != "True" ]]; do echo "waiting for vault-0 pod to run." && sleep 5; done
kubectl exec --stdin=true --tty=true vault-0 -- vault audit enable file file_path=stdout
}
#====================
#- Install DD Agent
#====================
function install_dd_agent()
{
if check_install 'helm status datadog-agent'
then
echo "Datadog agent is already installed"
return
fi
helm repo add datadog https://helm.datadoghq.com
helm repo update
#- This file is not being used currently used
tee -a $HOME/helm-ddagent-values.yml <<EOF
datadog:
logs:
enabled: true
containerCollectAll: true
EOF
while true
do
echo "Enter a valid DD API Key":
read key
response=$(curl -sX GET "https://api.datadoghq.com/api/v1/validate" \
-H "Content-Type: application/json" \
-H "DD-API-KEY: ${key}" | grep valid)
if test "x"$response != "x"
then
echo "Key is valid"
echo "Installing datadog-agent using Helm"
#- RELEASE_NAME can be anything you decide, In this example it is: datadog-agent
#helm install datadog-agent -f helm-ddagent-values.yml --set datadog.site='datadoghq.com' --set datadog.apiKey=$key datadog/datadog
# - You can provide values from a config file:
# curl -s https://raw.githubusercontent.com/DataDog/helm-charts/main/charts/datadog/values.yaml -o datadog-values.yaml
# helm install datadog-agent -f helm-ddagent-values.yml
# - You can also set individual values with --set option: https://github.com/Datadog/helm-charts/tree/main/charts/datadog#values
# helm install datadog-agent --set datadog.site='datadoghq.com' --set datadog.apiKey=$key datadog/datadog
# - You can also combine them both
#- helm upgrade datadog-agent -f datadog-values.yaml --set datadog.kubelet.tlsVerify='false' datadog/datadog
helm install datadog-agent \
--set datadog.site='datadoghq.com' \
--set datadog.apiKey=$key \
--set datadog.kubelet.tlsVerify='false' \
--set clusterAgent.enabled='true' \
--set datadog.kubeStateMetricsCore.enabled='true' \
--set datadog.logs.enabled='true' \
--set datadog.logs.containerCollectAll='true' \
datadog/datadog
echo "To test if everything's working fine use: kubectl exec -it datadog-agent-qkmkp -c agent -- agent status"
break
fi
done
}
#===================================================================
#- Datadog Agent - Remove
#===================================================================
function remove_dd_agent()
{
helm uninstall datadog-agent
}
#===================================================================
#- Vault UI - Port forward to 8200
#===================================================================
function vault_ui_port_forward()
{
VAULT_UI_STATUS=$(sudo netstat -tlnp | grep ":8200" | awk '{print $NF}')
if test "x"$VAULT_UI_STATUS != "x"
then
echo "Vault UI seems to be up already."$VAULT_UI_STATUS ". Killing this first..."
killpid=$(echo $VAULT_UI_STATUS | cut -f1 -d"/")
echo "PID to kill is " $killpid
sudo kill $killpid
vault_ui_port_forward
else
echo "Enabling port forward for Vault UI"
nohup kubectl port-forward --address 0.0.0.0 vault-0 8200:8200 &
fi
}
#===================================================================
#- Remove docker completely
#- https://docs.docker.com/engine/install/ubuntu/#uninstall-docker-engine
#===================================================================
function remove_docker()
{
sudo -E sh -c 'DEBIAN_FRONTEND=noninteractive apt-get purge -y -qq purge docker-ce docker-ce-cli containerd.io docker-compose-plugin'
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
}
#===================================================================
#- Selection Menu
#- Ref: https://askubuntu.com/questions/1705/how-can-i-create-a-select-menu-in-a-shell-script
#===================================================================
function show_menu()
{
check_sudo
while true
do
clear
echo "select the Operation:"
echo " 0) Setup aliases"
echo " 1) Install docker, jq, net-tools"
echo " 2) Install minikube, kubectl and helm"
echo " 3) Install and configure nginx (for minikube dashboard)"
echo " 4) minikube - Start with audit"
echo " 5) minikube - Start dashboard"
echo " 6) minikube clear audit log (experimental)"
echo " 7) Install Vault and Consul with Helm"
echo " 8) Vault - Enable K8s auth"
echo " 9) Vault - Port forward UI to port 8200"
echo " 10) Vault - Enable Audit logs"
echo " 11) Datadog - Install Agent with Helm"
echo " 12) Remove Vault and Consul"
echo " 13) Remove DD Agent"
echo " 14) Remove Docker"
echo " x) Exit"
read n
case $n in
0) setup_aliases; echo "Press enter to continue..."; read;;
1) install_basics; echo "Press enter to continue..."; read;;
2) install_kube_stuff; echo "Press enter to continue..."; read;;
3) install_nginx; echo "Press enter to continue..."; read;;
4) minikube_start_audit; echo "Press enter to continue..."; read;;
5) minikube_start_dashboard; echo "Press enter to continue..."; read;;
6) echo "Not doing it"; echo "Press enter to continue..."; read;; #minikube_clear_audit;;
7) install_vault_consul; echo "Press enter to continue..."; read;;
8) vault_enable_k8s_auth; echo "Press enter to continue..."; read;;
9) vault_ui_port_forward; echo "Press enter to continue..."; read;;
10) vault_enable_audit_logs; echo "Press enter to continue..."; read;;
11) install_dd_agent; echo "Press enter to continue..."; read;;
12) remove_vault_consul; echo "Press enter to continue..."; read;;
13) remove_dd_agent; echo "Press enter to continue..."; read;;
14) remove_docker; echo "Press enter to continue..."; read;;
x) exit 0;;
*) echo "invalid option"; echo "Press enter to continue..."; read;;
esac
done
}
function auto_install()
{
check_sudo;
setup_aliases;
install_basics;
install_kube_stuff;
install_nginx;
minikube_start_audit;
install_dd_agent;
minikube_start_dashboard;
install_vault_consul;
vault_enable_audit_logs;
vault_enable_k8s_auth;
vault_ui_port_forward;
}
#- Basically these are the two functions:
#show_menu
#auto_install
ERR_MSG="Script Usage: $(basename $0) -t <Type can be 'auto' for automatic or 'menu' for menu based>. Example: $(basename $0) -t auto"
#- Ref: https://linuxconfig.org/bash-script-flags-usage-with-arguments-examples
while getopts 't:' OPTION; do
case "$OPTION" in
t)
echo "Value provided is " $OPTARG
if [ $OPTARG != "auto" -a $OPTARG != "menu" ]; then
echo $ERR_MSG >&2
elif [ $OPTARG == "auto" ]; then
echo "Auto install"
auto_install;
elif [ $OPTARG == "menu" ]; then
echo "Menu based"
show_menu;
fi
;;
?)
echo $ERR_MSG >&2
exit 1
;;
esac
done
shift "$(($OPTIND -1))"
if [ $OPTIND -eq 1 ]; then echo $ERR_MSG; fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment