Created
April 1, 2025 23:43
-
-
Save linuxmalaysia/7782c879be1e22469d39bb1557505623 to your computer and use it in GitHub Desktop.
Script to set up Kibana using Podman with the hardened Wolfi image. This script should be run after setup_elasticsearch.sh.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Script to set up Kibana using Podman with the hardened Wolfi image, | |
# based on the official Docker documentation. | |
# Note: Using Wolfi images might have specific kernel or dependency requirements. | |
# https://www.elastic.co/guide/en/kibana/current/docker.html | |
# GNU GENERAL PUBLIC LICENSE Version 3 | |
# Harisfazillah Jamel and Google Gemini | |
# 2 Apr 2025 | |
# Script to set up Kibana using Podman with its own custom kibana.yml. | |
# This script should be run after setup_elasticsearch.sh. | |
set -e # Exit immediately if a command exits with a non-zero status. | |
# --- Determine Script's Directory --- | |
SCRIPT_DIR="$(dirname "$(realpath "$0")")" | |
# Get the directory where the script is located. | |
# dirname: Extracts the directory name from a path. | |
# realpath: Resolves symbolic links to their actual path. | |
# $0: Represents the path of the script being executed. | |
# --- Variables --- | |
ELK_BASE_DIR="${SCRIPT_DIR}" # Base directory is where the script is located. | |
ELK_DIR="${ELK_BASE_DIR}/elk-wolfi" # Directory for ELK-related files. | |
CERT_DIR="${ELK_DIR}/certs" # Directory for SSL certificates. | |
KIBANA_IMAGE_NAME="docker.elastic.co/kibana/kibana-wolfi" # Name of the Kibana Docker image. | |
KIBANA_CONTAINER_NAME="kib01" # Name for the Kibana container. | |
KIBANA_PORT="5601" # Port on which Kibana will be accessible. | |
NETWORK_NAME="elk-wolfi_elastic" # Name of the Podman network. Important for Elasticsearch/Kibana communication. | |
TEMP_CREDENTIALS_FILE="${ELK_DIR}/temp_credentials.txt" # File to store temporary credentials (like Elasticsearch password). | |
# --- Helper Functions --- | |
info() { | |
echo "--- $1 ---" # Function to print informational messages with a separator. | |
} | |
command_exists () { | |
command -v "$1" >/dev/null 2>&1 | |
# Checks if a command exists in the system's PATH. | |
# command -v: Checks if a command is available. | |
# >/dev/null 2>&1: Silences both standard output and standard error. | |
} | |
# --- Step 1: Check Prerequisites --- | |
info "Step 1: Check Prerequisites" | |
if ! command_exists podman; then | |
echo "Error: Podman is not installed. Please run the setup_elasticsearch.sh script first or install Podman." | |
exit 1 # Exit with an error code 1 to indicate failure. | |
fi | |
if ! command_exists podman-compose; then | |
echo "Error: podman-compose is not installed. Please run the setup_elasticsearch.sh script first or install podman-compose." | |
exit 1 | |
fi | |
# --- Step 2: Check for Certificate File --- | |
info "Step 2: Check for Elasticsearch Certificate" | |
CERT_FILE="${CERT_DIR}/http_ca.crt" # Define the path to the Elasticsearch certificate. | |
if [ ! -f "${CERT_FILE}" ]; then | |
echo "Error: Elasticsearch certificate file not found at '${CERT_FILE}'. Please ensure the setup_elasticsearch.sh script was run successfully." | |
exit 1 # Exit if the certificate file is not found. | |
fi | |
# --- Check Elasticsearch Network --- | |
info " Step 2.1: Check Elasticsearch Network" | |
if ! podman network exists "${NETWORK_NAME}"; then # Check if the network exists. | |
echo "Error: The Podman network '${NETWORK_NAME}' does not exist." | |
echo "Please ensure that the setup_elasticsearch.sh script was run successfully and created this network." | |
exit 1 | |
fi | |
info "Podman network '${NETWORK_NAME}' exists." | |
# --- Step 3: Check Elasticsearch Status and Get Version --- | |
info "Step 3: Check Elasticsearch Status and Get Version" | |
# Attempt to retrieve the Elasticsearch password from the temporary file and clean it | |
if [ -f "${TEMP_CREDENTIALS_FILE}" ]; then | |
ELASTIC_PASSWORD=$(grep "Elastic password set to:" "${TEMP_CREDENTIALS_FILE}" | sed 's/.*Elastic password set to: //' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') | |
# Get the Elasticsearch password from the temporary credentials file. | |
# grep: Finds the line containing "Elastic password set to:". | |
# sed: Used to extract the password from the line. | |
# s/.*Elastic password set to: //: Removes everything before the password. | |
# s/^[[:space:]]*//: Removes leading spaces. | |
# s/[[:space:]]*$//: Removes trailing spaces. | |
else | |
echo "Error: Temporary credentials file '${TEMP_CREDENTIALS_FILE}' not found. Please ensure the setup_elasticsearch.sh script was run successfully." | |
exit 1 | |
fi | |
if [ -z "${ELASTIC_PASSWORD}" ]; then | |
echo "Error: Elasticsearch password not found in '${TEMP_CREDENTIALS_FILE}'. Please check the file." | |
exit 1 | |
fi | |
ES_STATUS=$(curl -s --cacert "${CERT_FILE}" -u "elastic:${ELASTIC_PASSWORD}" "https://localhost:9200") | |
# Check the status of Elasticsearch. | |
# curl: Makes an HTTP request to Elasticsearch. | |
# -s: Silent mode. | |
# --cacert: Specifies the CA certificate for SSL verification. | |
# -u: Specifies the username and password for authentication. | |
# https://localhost:9200: The default Elasticsearch API endpoint. | |
if [[ "$ES_STATUS" == *"You Know, for Search"* ]]; then | |
info "Elasticsearch is running." | |
ELASTICSEARCH_VERSION=$(echo "$ES_STATUS" | jq -r '.version.number') | |
# Extract the Elasticsearch version from the JSON output. | |
# jq: A command-line JSON processor. | |
# -r: Raw output (prints the value without quotes). | |
# .version.number: JSON path to the version number. | |
info "Elasticsearch version found: ${ELASTICSEARCH_VERSION}" | |
else | |
echo "Error: Elasticsearch is not running or the status check failed." | |
echo "Status output: ${ES_STATUS}" | |
exit 1 | |
fi | |
# --- Step 4: Pull Kibana Docker Image --- | |
info "Step 4: Pull Kibana Docker Image" | |
KIBANA_IMAGE="${KIBANA_IMAGE_NAME}:${ELASTICSEARCH_VERSION}" # Tag the Kibana image with the Elasticsearch version. | |
podman pull "${KIBANA_IMAGE}" # Pull the Kibana image from the container registry. | |
# --- Step 5: Get Default Kibana Configuration --- | |
info "Step 5: Get Default Kibana Configuration" | |
TEMP_KIBANA_CONTAINER="temp_kib01" # Name for a temporary Kibana container. | |
# --- Step 5.1: Create ELK Directory on Host --- | |
info "Step 5.1: Create ELK Directory on Host" | |
mkdir -p "${ELK_DIR}" # Create the ELK directory on the host if it doesn't exist. | |
echo "Starting temporary Kibana container '${TEMP_KIBANA_CONTAINER}' to extract default config..." | |
podman run --name "${TEMP_KIBANA_CONTAINER}" --network "${NETWORK_NAME}" -d "${KIBANA_IMAGE}" sleep infinity | |
# Start a temporary Kibana container in detached mode. | |
# podman run: Runs a container. | |
# --name: Assigns a name to the container. | |
# --network: Connects the container to the specified network. | |
# -d: Detached mode (runs in the background). | |
# sleep infinity: Keeps the container running indefinitely. We use this because we only need the container to be running to copy the file, not to execute a service. | |
if [ $? -eq 0 ]; then # Check if the podman run command was successful. | |
echo "Copying default kibana.yml from container..." | |
podman cp "${TEMP_KIBANA_CONTAINER}:/usr/share/kibana/config/kibana.yml" "${ELK_DIR}/kibana.yml" | |
# Copy the default kibana.yml file from the container to the host. | |
# podman cp: Copies files between a container and the host. | |
echo "Default kibana.yml copied to ${ELK_DIR}/kibana.yml. Please review and customize it." | |
echo "Stopping and removing temporary container '${TEMP_KIBANA_CONTAINER}'..." | |
podman stop "${TEMP_KIBANA_CONTAINER}" # Stop the temporary container. | |
podman rm "${TEMP_KIBANA_CONTAINER}" # Remove the temporary container. | |
else | |
echo "Error starting temporary Kibana container. Skipping default config copy." | |
exit 1 | |
fi | |
# --- Step 6: Start a Kibana container using podman-compose with volume and custom config --- | |
info "Step 6: Start a Kibana container using podman-compose with volume and custom config" | |
cat > "${ELK_DIR}/podman-compose-kibana.yml" <<EOL | |
version: '3.8' # Use version 3.8 of the Compose file format. Specifies the version of the Compose file syntax. | |
services: | |
kibana: | |
image: ${KIBANA_IMAGE} # The Docker image to use for the Kibana service. | |
container_name: ${KIBANA_CONTAINER_NAME} # The name of the container. | |
networks: | |
- ${NETWORK_NAME} # Connect the Kibana container to the specified network, allowing it to communicate with Elasticsearch. | |
ports: | |
- "${KIBANA_PORT}:${KIBANA_PORT}" # Map the Kibana port (5601) on the host to the same port in the container. | |
volumes: | |
- kibana_data:/data/kibana_data # Mount a volume for Kibana data. This persists data across container restarts. | |
- ./kibana.yml:/usr/share/kibana/config/kibana.yml # Mount custom kibana.yml to standard config dir | |
volumes: | |
kibana_data: # Declare a named volume for Kibana data. This allows Podman to manage the volume. | |
networks: | |
${NETWORK_NAME}: | |
external: true # Declare the network as external, meaning it was created outside of this Compose file. | |
EOL | |
# podman-compose.yml: This file defines how to set up and run the Kibana container. | |
# version: The version of the Compose file format. | |
# services: Defines the services that make up the application (in this case, just Kibana). | |
# kibana: Defines the Kibana service. | |
# image: The Docker image to use for Kibana. | |
# container_name: The name of the container. | |
# networks: The networks to connect the container to. | |
# ports: Port mappings between the host and the container. | |
# environment: Environment variables for the Kibana container. | |
# volumes: Volume mappings for persistent data and configuration. | |
# networks: Defines the networks used by the services. | |
# external: Indicates that the network was created outside of this Compose file. | |
cd "${ELK_DIR}" # Change to the directory containing the podman-compose file. | |
podman-compose -f podman-compose-kibana.yml up -d | |
# Start Kibana using podman-compose. | |
# -f: Specifies the Compose file to use. | |
# up: Starts the services defined in the Compose file. | |
# -d: Runs the services in detached mode (in the background). | |
# --- Step 7: Wait for Kibana Container to be Running --- | |
info "Step 7: Wait for Kibana Container to be Running" | |
MAX_WAIT_SECONDS=60 # Maximum number of seconds to wait for Kibana to start. | |
echo "Please wait for Kibana to start..." | |
for i in $(seq "$MAX_WAIT_SECONDS" -1 1); do | |
echo "Waiting for Kibana to start... $i seconds remaining..." | |
podman ps -a --filter name="${KIBANA_CONTAINER_NAME}" | |
# Check the status of the Kibana container. | |
# podman ps -a: Lists all containers (running and stopped). | |
# --filter: Filters the output by container name. | |
sleep 1 # Wait for 1 second before checking again. | |
done | |
echo "Kibana start process waiting complete. You can check the status above." | |
# --- Step 8: Get Elasticsearch Container IP Address --- | |
info "Step 8: Get Elasticsearch Container IP Address" | |
ES01_IP=$(podman inspect es01 | grep "elk-wolfi_elastic" -A 10 | grep "IPAddress" | sed -e 's/.*: "//' -e 's/,"//' -e 's/ //g') | |
echo "Elasticsearch (es01) IP Address: ${ES01_IP}" | |
# Get the IP address of the Elasticsearch container. This is needed for Kibana configuration. | |
# podman inspect: Retrieves detailed information about a container. | |
# es01: The name of the Elasticsearch container. | |
# grep "elk-wolfi_elastic": Filters the output to show information about the specified network. | |
# -A 10: Displays the 10 lines after the line containing the network name. | |
# grep "IPAddress": Filters the output to show the line containing the IP address. | |
# sed: Extracts the IP address from the line. | |
# -e 's/.*: "//': Removes everything before the IP address and the colon. | |
# -e 's/,"//': Removes the comma and double quote after the IP address. | |
# -e 's/ //g': Removes any remaining spaces. | |
# --- Step 9: Retrieve and Clean Kibana Enrollment Token --- | |
info "Retrieving Kibana enrollment token..." | |
KIBANA_ENROLLMENT_TOKEN=$(podman exec -it es01 /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibana 2>>"${TEMP_CREDENTIALS_FILE}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') | |
# Retrieve the Kibana enrollment token from the Elasticsearch container. This token is used to enroll Kibana into the Elasticsearch cluster. | |
# podman exec: Executes a command inside a running container. | |
# -it: Interactive (allows you to see output). | |
# es01: The name of the Elasticsearch container (assumed to be running). | |
# /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibana: The command to generate the enrollment token for Kibana. | |
# 2>>"${TEMP_CREDENTIALS_FILE}": Redirect standard error (2) to the temporary credentials file, appending to it. | |
# sed: Remove leading/trailing spaces. | |
# -e 's/^[[:space:]]*//': Removes leading spaces. | |
# -e 's/[[:space:]]*$//': Removes trailing spaces. | |
if [ -n "${KIBANA_ENROLLMENT_TOKEN}" ]; then #check if the token is not empty | |
echo "Kibana enrollment token: ${KIBANA_ENROLLMENT_TOKEN}" | |
if grep -q "^Kibana enrollment token:" "${TEMP_CREDENTIALS_FILE}"; then | |
# Replace the existing line | |
sed -i "s/^Kibana enrollment token:.*$/Kibana enrollment token: ${KIBANA_ENROLLMENT_TOKEN}/" "${TEMP_CREDENTIALS_FILE}" | |
# sed -i : in-place substitution | |
# s/old/new/ : substitute old with new | |
# ^Kibana enrollment token:.*$ : find the line starting with Kibana enrollment and replace the whole line. | |
else | |
# Append a new line | |
echo "Kibana enrollment token: ${KIBANA_ENROLLMENT_TOKEN}" >> "${TEMP_CREDENTIALS_FILE}" | |
fi | |
else | |
echo "Error retrieving Kibana enrollment token. Check ${TEMP_CREDENTIALS_FILE}" | |
fi | |
echo "" | |
info "Kibana setup script complete!" | |
echo "" | |
info "You can access the Kibana from your Internet Browser with this URL http://localhost:5601" | |
echo "" | |
info "Retrieve Kibana Verification Code:" | |
podman exec -it kib01 /usr/share/kibana/bin/kibana-verification-code | |
# Display the command to retrieve the Kibana verification code. This code is needed for the initial setup of Kibana. | |
# podman exec: Execute command in container. | |
# -it: Interactive shell. | |
# kib01: The name of the Kibana container. | |
# /usr/share/kibana/bin/kibana-verification-code: The command to display the verification code. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment