cloudstack/scripts/util/keystore-cert-import
Nicolas Vazquez eac357cb77
kvm: Secure KVM VNC Console Access Using the CA Framework (#7015)
This PR allows securing the console access through CloudStack to the virtual machines running on KVM. The secure access is achieved through the generated certificates for the CA Framework in CloudStack, that provides mutual TLS connections between agents. These certificates are used to also secure the connection between the console proxies and the VNC ports for VM console access.

This feature is only supported on the KVM hypervisor

Design Document: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Secure+KVM+VNC+connection+using+the+CA+framework
2023-01-27 17:22:06 +05:30

144 lines
5.6 KiB
Bash
Executable File

#!/bin/bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
PROPS_FILE="$1"
KS_PASS="$2"
KS_FILE="$3"
MODE="$4"
CERT_FILE="$5"
CERT=$(echo "$6" | tr '^' '\n' | tr '~' ' ')
CACERT_FILE="$7"
CACERT=$(echo "$8" | tr '^' '\n' | tr '~' ' ')
PRIVKEY_FILE="$9"
PRIVKEY=$(echo "${10}" | tr '^' '\n' | tr '~' ' ')
ALIAS="cloud"
SYSTEM_FILE="/var/cache/cloud/cmdline"
LIBVIRTD_FILE="/etc/libvirt/libvirtd.conf"
if [ ! -f "$LIBVIRTD_FILE" ]; then
# Re-use existing password or use the one provided
while [ ! -d /usr/local/cloud/systemvm/conf ]; do sleep 1; done
if [ -f "$PROPS_FILE" ]; then
OLD_PASS=$(sed -n '/keystore.passphrase/p' "$PROPS_FILE" 2>/dev/null | sed 's/keystore.passphrase=//g' 2>/dev/null)
if [ ! -z "${OLD_PASS// }" ]; then
KS_PASS="$OLD_PASS"
else
sed -i "/keystore.passphrase.*/d" $PROPS_FILE 2> /dev/null || true
echo "keystore.passphrase=$KS_PASS" >> $PROPS_FILE
fi
fi
fi
# Find keystore password
KS_PASS=$(sed -n '/keystore.passphrase/p' "$PROPS_FILE" 2>/dev/null | sed 's/keystore.passphrase=//g' 2>/dev/null)
if [ -z "${KS_PASS// }" ]; then
echo "Failed to find keystore passphrase from file: $PROPS_FILE, quiting!"
exit 1
fi
# Import certificate
if [ ! -z "${CERT// }" ]; then
echo "$CERT" > "$CERT_FILE"
elif [ ! -f "$CERT_FILE" ]; then
echo "Cannot find certificate file: $CERT_FILE, exiting"
exit
fi
# Import ca certs
if [ ! -z "${CACERT// }" ]; then
echo "$CACERT" > "$CACERT_FILE"
elif [ ! -f "$CACERT_FILE" ]; then
echo "Cannot find ca certificate file: $CACERT_FILE, exiting!"
exit
fi
# Import cacerts into the keystore
awk '/-----BEGIN CERTIFICATE-----?/{n++}{print > "cloudca." n }' "$CACERT_FILE"
for caChain in $(ls cloudca.*); do
keytool -delete -noprompt -alias "$caChain" -keystore "$KS_FILE" -storepass "$KS_PASS" > /dev/null 2>&1 || true
keytool -import -noprompt -storepass "$KS_PASS" -trustcacerts -alias "$caChain" -file "$caChain" -keystore "$KS_FILE" > /dev/null 2>&1
done
rm -f cloudca.*
# Stop cloud service in systemvm
if [ "$MODE" == "ssh" ] && [ -f $SYSTEM_FILE ]; then
systemctl stop cloud > /dev/null 2>&1
fi
# Import private key if available
if [ ! -z "${PRIVKEY// }" ]; then
echo "$PRIVKEY" > "$PRIVKEY_FILE"
else
> "$PRIVKEY_FILE"
fi
if [ -f "$PRIVKEY_FILE" ] && [ -s "$PRIVKEY_FILE" ]; then
# Re-initialize keystore when private key is provided
keytool -delete -noprompt -alias "$ALIAS" -keystore "$KS_FILE" -storepass "$KS_PASS" 2>/dev/null || true
openssl pkcs12 -export -name "$ALIAS" -in "$CERT_FILE" -inkey "$PRIVKEY_FILE" -out "$KS_FILE.p12" -password pass:"$KS_PASS" > /dev/null 2>&1
keytool -importkeystore -srckeystore "$KS_FILE.p12" -destkeystore "$KS_FILE" -srcstoretype PKCS12 -alias "$ALIAS" -deststorepass "$KS_PASS" -destkeypass "$KS_PASS" -srcstorepass "$KS_PASS" -srckeypass "$KS_PASS" > /dev/null 2>&1
else
# Import certificate into the keystore
keytool -import -storepass "$KS_PASS" -alias "$ALIAS" -file "$CERT_FILE" -keystore "$KS_FILE" > /dev/null 2>&1 || true
# Export private key from keystore
rm -f "$PRIVKEY_FILE"
keytool -importkeystore -srckeystore "$KS_FILE" -destkeystore "$KS_FILE.p12" -deststoretype PKCS12 -srcalias "$ALIAS" -deststorepass "$KS_PASS" -destkeypass "$KS_PASS" -srcstorepass "$KS_PASS" -srckeypass "$KS_PASS" > /dev/null 2>&1
openssl pkcs12 -in "$KS_FILE.p12" -nodes -nocerts -nomac -password pass:"$KS_PASS" 2>/dev/null | openssl rsa -out "$PRIVKEY_FILE" > /dev/null 2>&1
fi
rm -f "$KS_FILE.p12"
# Secure libvirtd on cert import
if [ -f "$LIBVIRTD_FILE" ]; then
mkdir -p /etc/pki/CA
mkdir -p /etc/pki/libvirt/private
ln -sf /etc/cloudstack/agent/cloud.ca.crt /etc/pki/CA/cacert.pem
ln -sf /etc/cloudstack/agent/cloud.crt /etc/pki/libvirt/clientcert.pem
ln -sf /etc/cloudstack/agent/cloud.crt /etc/pki/libvirt/servercert.pem
ln -sf /etc/cloudstack/agent/cloud.key /etc/pki/libvirt/private/clientkey.pem
ln -sf /etc/cloudstack/agent/cloud.key /etc/pki/libvirt/private/serverkey.pem
# VNC TLS directory and certificates
mkdir -p /etc/pki/libvirt-vnc
ln -sf /etc/pki/CA/cacert.pem /etc/pki/libvirt-vnc/ca-cert.pem
ln -sf /etc/pki/libvirt/servercert.pem /etc/pki/libvirt-vnc/server-cert.pem
ln -sf /etc/pki/libvirt/private/serverkey.pem /etc/pki/libvirt-vnc/server-key.pem
cloudstack-setup-agent -s > /dev/null
fi
# Update ca-certs if we're in systemvm
if [ -f "$SYSTEM_FILE" ]; then
mkdir -p /usr/local/share/ca-certificates/cloudstack
cp "$CACERT_FILE" /usr/local/share/ca-certificates/cloudstack/ca.crt
chmod 755 /usr/local/share/ca-certificates/cloudstack
chmod 644 /usr/local/share/ca-certificates/cloudstack/ca.crt
update-ca-certificates > /dev/null 2>&1 || true
# Ensure cloud service is running in systemvm
if [ "$MODE" == "ssh" ]; then
systemctl start cloud > /dev/null 2>&1
fi
fi
# Fix file permission
chmod 600 $CACERT_FILE
chmod 600 $CERT_FILE
chmod 600 $PRIVKEY_FILE