diff --git a/simple_vm_client/openstack_connector/openstack_connector.py b/simple_vm_client/openstack_connector/openstack_connector.py index f7c6cae..3928d1f 100644 --- a/simple_vm_client/openstack_connector/openstack_connector.py +++ b/simple_vm_client/openstack_connector/openstack_connector.py @@ -499,9 +499,11 @@ def create_save_metadata_auth_token_script( # Use a unique placeholder in the script for replacement placeholder = "REPLACE_WITH_ACTUAL_TOKEN" + endpoint_placeholder = "REPLACE_WITH_ACTUAL_METADATA_INFO_ENDPOINT" # Replace the placeholder with the actual token text = text.replace(placeholder, token) + text = text.replace(endpoint_placeholder, metadata_endpoint) text = encodeutils.safe_encode(text.encode("utf-8")) @@ -1331,15 +1333,9 @@ def create_userdata( unlock_ubuntu_user_script.encode("utf-8") ) init_script = unlock_ubuntu_user_script_encoded - if metadata_token and metadata_endpoint: - save_metadata_token_script = self.create_save_metadata_auth_token_script( - token=metadata_token, metadata_endpoint=metadata_endpoint - ) - init_script = ( - init_script - + encodeutils.safe_encode("\n".encode("utf-8")) - + save_metadata_token_script - ) + logger.info( + f"Metadata token {metadata_token} | Metadata Endpoint {metadata_endpoint}" + ) if additional_keys: add_key_script = self.create_add_keys_script(keys=additional_keys) init_script = ( @@ -1357,6 +1353,16 @@ def create_userdata( + encodeutils.safe_encode("\n".encode("utf-8")) + mount_script ) + if metadata_token and metadata_endpoint: + save_metadata_token_script = self.create_save_metadata_auth_token_script( + token=metadata_token, metadata_endpoint=metadata_endpoint + ) + init_script = ( + init_script + + encodeutils.safe_encode("\n".encode("utf-8")) + + save_metadata_token_script + ) + return init_script def start_server( diff --git a/simple_vm_client/openstack_connector/scripts/bash/save_metadata_auth_token.sh b/simple_vm_client/openstack_connector/scripts/bash/save_metadata_auth_token.sh index da37f1c..04be6b4 100644 --- a/simple_vm_client/openstack_connector/scripts/bash/save_metadata_auth_token.sh +++ b/simple_vm_client/openstack_connector/scripts/bash/save_metadata_auth_token.sh @@ -2,44 +2,100 @@ # Use clear placeholders that will be replaced in the Python script TOKEN_ESCAPED='REPLACE_WITH_ACTUAL_TOKEN' -ENDPOINT_ESCAPED='REPLACE_WITH_ACTUAL_ENDPOINT' +METADATA_INFO_ENDPOINT_ESCAPED='REPLACE_WITH_ACTUAL_METADATA_INFO_ENDPOINT' # Create a configuration file with the token in /etc/simplevm directory CONFIG_DIR="/etc/simplevm" -CONFIG_FILE_PATH="$CONFIG_DIR/.metadata_config.env" +CONFIG_FILE_PATH="$CONFIG_DIR/metadata_config.env" -echo "METADATA_ACCESS_TOKEN='$TOKEN_ESCAPED'" > "$CONFIG_FILE_PATH" -echo "METADATA_SERVER_ENDPOINT='$ENDPOINT_ESCAPED'" >> "$CONFIG_FILE_PATH" +# Check if the config directory already exists +if [ -d "$CONFIG_DIR" ]; then + echo "Config directory $CONFIG_DIR already exists." +else + # Create the config directory with permissions that allow only root to read and write it + mkdir -p "$CONFIG_DIR" || { echo "Error creating directory $CONFIG_DIR"; exit 1; } + chmod 700 "$CONFIG_DIR" + chown root:root "$CONFIG_DIR" +fi -# Secure the file permissions so only root can read it +# Validate token value +if [ -z "${TOKEN_ESCAPED}" ]; then + echo "Error: Token cannot be empty" + exit 1 +fi + +# Create the config file with permissions that allow only root to read it +echo "METADATA_ACCESS_TOKEN=$TOKEN_ESCAPED" > "$CONFIG_FILE_PATH" || { echo "Error writing to file $CONFIG_FILE_PATH"; exit 1; } chmod 600 "$CONFIG_FILE_PATH" chown root:root "$CONFIG_FILE_PATH" +# Validate metadata info endpoint value +if [ -z "${METADATA_INFO_ENDPOINT_ESCAPED}" ]; then + echo "Error: Metadata info endpoint cannot be empty" + exit 1 +fi + +echo "METADATA_INFO_ENDPOINT=$METADATA_INFO_ENDPOINT_ESCAPED" >> "$CONFIG_FILE_PATH" || { echo "Error writing to file $CONFIG_FILE_PATH"; exit 1; } + +# Check if jq is installed +if ! command -v jq &> /dev/null; then + echo "jq is not installed. Installing..." + sudo apt-get update && sudo apt-get install -y jq || { echo "Error installing jq"; exit 1; } +fi + # Create the /etc/simplevm/get_metadata.sh script to fetch metadata using the saved token SCRIPT_DIR="$CONFIG_DIR" SCRIPT_NAME="get_metadata.sh" SCRIPT_PATH="$SCRIPT_DIR/$SCRIPT_NAME" -echo "#!/bin/bash" > "$SCRIPT_PATH" -echo "source $CONFIG_FILE_PATH" >> "$SCRIPT_PATH" -echo "" >> "$SCRIPT_PATH" -echo "# Define the metadata server endpoint and local machine IP" >> "$SCRIPT_PATH" -echo "SERVER_ENDPOINT=\\\\"$METADATA_SERVER_ENDPOINT\\\\"" >> "$SCRIPT_PATH" -echo "LOCAL_IP=\\\\$(ip route get 8.8.8.8 | awk '{print \\\\$7}' | tr -d '\\\\n')" >> "$SCRIPT_PATH" -echo "" >> "$SCRIPT_PATH" -echo "# Construct the URL" >> "$SCRIPT_PATH" -echo "URL=\\\\"\\\\${SERVER_ENDPOINT}/\\\\${LOCAL_IP}\\\\"" >> "$SCRIPT_PATH" -echo "" >> "$SCRIPT_PATH" -echo "# Define the auth header with the token" >> "$SCRIPT_PATH" -echo "AUTH_HEADER=\\\\"auth_token: \\\\${METADATA_ACCESS_TOKEN}\\\\"" >> "$SCRIPT_PATH" -echo "" >> "$SCRIPT_PATH" -echo "# Fetch the JSON response from the URL" >> "$SCRIPT_PATH" -echo "response=\\\\$(curl -s -X GET \\\\"\\\\$URL\\\\" -H \\\\"\\\\$AUTH_HEADER\\\\")" >> "$SCRIPT_PATH" -echo "" >> "$SCRIPT_PATH" -echo "echo \\\\"Response:\\\\"" >> "$SCRIPT_PATH" -echo "echo \\\\"\\\\$response\\\\"" >> "$SCRIPT_PATH" - -# Make the script executable +cat <<'EOF' > "$SCRIPT_PATH" +#!/bin/bash +source /etc/simplevm/metadata_config.env + +# Construct the URL with hostname query param +INFO_ENDPOINT_URL="${METADATA_INFO_ENDPOINT}?hostname=$(hostname)" + +# Define the auth header with the token +AUTH_HEADER="auth_token: ${METADATA_ACCESS_TOKEN}" + +# Get real metadata endpoint from config if available +REAL_METADATA_ENDPOINT=$(grep '^REAL_METADATA_ENDPOINT=' "/etc/simplevm/metadata_config.env" | cut -d '=' -f 2-) + +if [ -z "${REAL_METADATA_ENDPOINT}" ]; then + # Fetch the JSON response from the info endpoint to get real metadata endpoint + info_response=$(curl -s -X GET "${INFO_ENDPOINT_URL}" -H "${AUTH_HEADER}") + + if [ $? -ne 0 ]; then + echo "Error: Failed to fetch metadata endpoint" + exit 1 + fi + + # Validate the JSON response + if ! jq -e '.metadata_endpoint' <<< "${info_response}" &> /dev/null; then + echo "Error: Invalid JSON response from metadata endpoint" + exit 1 + fi + + # Extract the actual metadata endpoint from the response + REAL_METADATA_ENDPOINT=$(jq -r '.metadata_endpoint' <<< "${info_response}") + + # Save real metadata endpoint to config + echo "REAL_METADATA_ENDPOINT=${REAL_METADATA_ENDPOINT}" >> "/etc/simplevm/metadata_config.env" +fi + +# Fetch the actual metadata from the extracted endpoint +metadata_response=$(curl -s -X GET "${REAL_METADATA_ENDPOINT}" -H "${AUTH_HEADER}") + +if [ $? -ne 0 ]; then + echo "Error: Failed to fetch metadata" + exit 1 +fi + +echo "Response:" +echo "${metadata_response}" +EOF + +# Make the script executable and owned by root chmod 700 "$SCRIPT_PATH" chown root:root "$SCRIPT_PATH"