openstack-operator/devstack/lib/barbican

616 lines
20 KiB
Bash

#!/usr/bin/env bash
# Install and start **Barbican** service
# To enable a minimal set of Barbican features, add the following to localrc:
# enable_service barbican-svc barbican-retry barbican-keystone-listener
#
# Dependencies:
# - functions
# - OS_AUTH_URL for auth in api
# - DEST set to the destination directory
# - SERVICE_PASSWORD, SERVICE_PROJECT_NAME for auth in api
# - STACK_USER service user
# stack.sh
# ---------
# install_barbican
# configure_barbican
# init_barbican
# start_barbican
# stop_barbican
# cleanup_barbican
# Save trace setting
XTRACE=$(set +o | grep xtrace)
set +o xtrace
# PyKMIP configuration
PYKMIP_SERVER_KEY=${PYKMIP_SERVER_KEY:-$INT_CA_DIR/private/pykmip-server.key}
PYKMIP_SERVER_CERT=${PYKMIP_SERVER_CERT:-$INT_CA_DIR/pykmip-server.crt}
PYKMIP_CLIENT_KEY=${PYKMIP_CLIENT_KEY:-$INT_CA_DIR/private/pykmip-client.key}
PYKMIP_CLIENT_CERT=${PYKMIP_CLIENT_CERT:-$INT_CA_DIR/pykmip-client.crt}
PYKMIP_CA_PATH=${PYKMIP_CA_PATH:-$INT_CA_DIR/ca-chain.pem}
# Functions
# ---------
# TODO(john-wood-w) These 'magic' functions are called by devstack to enable
# a given service (so the name between 'is_' and '_enabled'). Currently the
# Zuul infra gate configuration (at https://github.com/openstack-infra/project-config/blob/master/jenkins/jobs/barbican.yaml)
# only enables the 'barbican' service. So the two functions below, for the two
# services we wish to run, have to key off of that lone 'barbican' selection.
# Once the Zuul config is updated to add these two services properly, then
# these functions should be replaced by the single method below.
# !!!! Special thanks to rm_work for figuring this out !!!!
function is_barbican-retry_enabled {
[[ ,${ENABLED_SERVICES} =~ ,"barbican" ]] && return 0
}
function is_barbican-svc_enabled {
[[ ,${ENABLED_SERVICES} =~ ,"barbican" ]] && return 0
}
function is_barbican-keystone-listener_enabled {
[[ ,${ENABLED_SERVICES} =~ ,"barbican" ]] && return 0
}
# TODO(john-wood-w) Replace the above two functions with the one below once
# Zuul is update per above.
## Test if any Barbican services are enabled
## is_barbican_enabled
#function is_barbican_enabled {
# [[ ,${ENABLED_SERVICES} =~ ,"barbican-" ]] && return 0
# return 1
#}
# cleanup_barbican - Remove residual data files, anything left over from previous
# runs that a clean run would need to clean up
function cleanup_barbican {
if is_service_enabled barbican-vault; then
# Kill the vault process, screen session and remove the generated files
# during installation.
local session_name="barbican_vault"
local vault_token_file="${BARBICAN_DIR}/vault_root_token_id"
existing_ses=$(screen -ls | grep ${session_name} | awk '{print $1}')
if [[ -n "${existing_ses}" ]]; then
screen -S ${existing_ses} -X quit
fi
sudo pkill -f -9 "vault server"
sudo rm -f ${vault_token_file} vault.log
fi
}
# configure_barbicanclient - Set config files, create data dirs, etc
function configure_barbicanclient {
setup_dev_lib "python-barbicanclient"
}
# configure_dogtag_plugin - Change config to use dogtag plugin
function configure_dogtag_plugin {
sudo openssl pkcs12 -in /root/.dogtag/pki-tomcat/ca_admin_cert.p12 -passin pass:PASSWORD -out $BARBICAN_CONF_DIR/kra_admin_cert.pem -nodes
sudo chown $USER $BARBICAN_CONF_DIR/kra_admin_cert.pem
iniset $BARBICAN_CONF dogtag_plugin dogtag_port 8373
iniset $BARBICAN_CONF dogtag_plugin pem_path "$BARBICAN_CONF_DIR/kra_admin_cert.pem"
iniset $BARBICAN_CONF dogtag_plugin dogtag_host localhost
iniset $BARBICAN_CONF dogtag_plugin nss_db_path '/etc/barbican/alias'
iniset $BARBICAN_CONF dogtag_plugin nss_db_path_ca '/etc/barbican/alias-ca'
iniset $BARBICAN_CONF dogtag_plugin nss_password 'password123'
iniset $BARBICAN_CONF dogtag_plugin simple_cmc_profile 'caOtherCert'
iniset $BARBICAN_CONF dogtag_plugin ca_expiration_time 1
iniset $BARBICAN_CONF dogtag_plugin plugin_working_dir '/etc/barbican/dogtag'
iniset $BARBICAN_CONF secretstore enabled_secretstore_plugins dogtag_crypto
iniset $BARBICAN_CONF certificate enabled_certificate_plugins dogtag
}
# configure_barbican - Set config files, create data dirs, etc
function configure_barbican {
setup_develop $BARBICAN_DIR
[ ! -d $BARBICAN_CONF_DIR ] && sudo mkdir -m 755 -p $BARBICAN_CONF_DIR
sudo chown $USER $BARBICAN_CONF_DIR
[ ! -d $BARBICAN_API_LOG_DIR ] && sudo mkdir -m 755 -p $BARBICAN_API_LOG_DIR
sudo chown $USER $BARBICAN_API_LOG_DIR
[ ! -d $BARBICAN_CONF_DIR ] && sudo mkdir -m 755 -p $BARBICAN_CONF_DIR
sudo chown $USER $BARBICAN_CONF_DIR
# Copy the barbican config files to the config dir
cp $BARBICAN_DIR/etc/barbican/barbican-api-paste.ini $BARBICAN_CONF_DIR
cp -R $BARBICAN_DIR/etc/barbican/vassals $BARBICAN_CONF_DIR
# Copy functional test config
cp $BARBICAN_DIR/etc/barbican/barbican-functional.conf $BARBICAN_CONF_DIR
# Enable DEBUG
iniset $BARBICAN_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL
# Set the host_href
iniset $BARBICAN_CONF DEFAULT host_href "$BARBICAN_HOST_HREF"
# Enable logging to stderr to have log also in the screen window
iniset $BARBICAN_CONF DEFAULT use_stderr True
# Format logging
if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then
setup_colorized_logging $BARBICAN_CONF DEFAULT project user
fi
# Set the database connection url
BARBICAN_DATABASE_USER=$(get_data_from_secret barbican-mysql openstack USER)
BARBICAN_DATABASE_PASSWORD=$(get_data_from_secret barbican-mysql openstack PASSWORD)
BARBICAN_DATABASE_NAME=$(get_data_from_secret barbican-mysql openstack DATABASE)
iniset $BARBICAN_CONF DEFAULT sql_connection "mysql+pymysql://$BARBICAN_DATABASE_USER:$BARBICAN_DATABASE_PASSWORD@barbican-mysql-master/$BARBICAN_DATABASE_NAME?charset=utf8"
# Disable auto-migration when deploying Barbican
iniset $BARBICAN_CONF DEFAULT db_auto_create False
# Increase default request buffer size, keystone auth PKI tokens can be very long
iniset $BARBICAN_CONF_DIR/vassals/barbican-api.ini uwsgi buffer-size 65535
# Rabbit settings
if is_service_enabled rabbit; then
iniset $BARBICAN_CONF DEFAULT transport_url rabbit://$RABBIT_USERID:$RABBIT_PASSWORD@$RABBIT_HOST:5672
else
echo_summary "Barbican requires that the RabbitMQ service is enabled"
fi
write_uwsgi_config "$BARBICAN_UWSGI_CONF" "$BARBICAN_WSGI" "/key-manager"
## Set up keystone
# Turn on the middleware
iniset $BARBICAN_PASTE_CONF 'pipeline:barbican_api' pipeline 'barbican-api-keystone'
# Set the keystone parameters
configure_keystone_authtoken_middleware $BARBICAN_CONF barbican
# NOTE(Alex): Operator stuff for memcached
iniset $BARBICAN_CONF keystone_authtoken memcached_servers "mcrouter-memcached-barbican:11211"
# Enable the keystone listener
iniset $BARBICAN_CONF keystone_notifications enable True
iniset $BARBICAN_CONF keystone_notifications control_exchange 'keystone'
}
# init_barbican - Initialize etc.
function init_barbican {
kubectl create secret generic barbican-config -n openstack \
--from-file=/etc/barbican/barbican.conf \
--from-file=/etc/barbican/barbican-api-paste.ini \
--from-file=/etc/barbican/barbican-functional.conf
recreate_database barbican utf8
}
# install_barbican - Collect source and prepare
function install_barbican {
echo noop
}
# install_barbicanclient - Collect source and prepare
function install_barbicanclient {
if use_library_from_git "python-barbicanclient"; then
git_clone_by_name "python-barbicanclient"
setup_dev_lib "python-barbicanclient"
fi
}
# start_barbican - Start running processes, including screen
function start_barbican {
# Start the Barbican service up.
kubernetes_rollout_restart daemonset/barbican
kubernetes_rollout_status daemonset/barbican
proxy_pass_to_kubernetes /key-manager barbican barbican-wsgi-api
# Pause while the barbican-svc populates the database, otherwise the retry
# service below might try to do this at the same time, leading to race
# conditions.
sleep 10
# Start the retry scheduler server up.
run_process barbican-retry "$BARBICAN_BIN_DIR/barbican-retry --config-file=$BARBICAN_CONF_DIR/barbican.conf"
# Start the barbican-keystone-listener
run_process barbican-keystone-listener "$BARBICAN_BIN_DIR/barbican-keystone-listener --config-file=$BARBICAN_CONF_DIR/barbican.conf"
}
# stop_barbican - Stop running processes
function stop_barbican {
# This will eventually be refactored to work like
# Solum and Manila (script to kick off a wsgiref server)
# For now, this will stop uWSGI rather than have it hang
killall -9 uwsgi
# This cleans up the PID file, but uses pkill so Barbican
# uWSGI emperor process doesn't actually stop
stop_process barbican-svc
stop_process barbican-retry
stop_process barbican-keystone-listener
}
function get_id {
echo `"$@" | awk '/ id / { print $4 }'`
}
function create_barbican_accounts {
#
# Setup Default Admin User
#
SERVICE_PROJECT=$(openstack project list | awk "/ $SERVICE_PROJECT_NAME / { print \$2 }")
ADMIN_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
BARBICAN_USER=$(openstack user create \
--password "$SERVICE_PASSWORD" \
--project $SERVICE_PROJECT \
--email "barbican@example.com" \
barbican \
| grep " id " | get_field 2)
openstack role add --project $SERVICE_PROJECT \
--user $BARBICAN_USER \
$ADMIN_ROLE
#
# Setup Default service-admin User
#
SERVICE_ADMIN=$(get_id openstack user create \
--password "$SERVICE_PASSWORD" \
--email "service-admin@example.com" \
"service-admin")
SERVICE_ADMIN_ROLE=$(get_id openstack role create \
"key-manager:service-admin")
openstack role add \
--user "$SERVICE_ADMIN" \
--project "$SERVICE_PROJECT" \
"$SERVICE_ADMIN_ROLE"
#
# Setup RBAC User Projects and Roles
#
PASSWORD="barbican"
PROJECT_A_ID=$(get_id openstack project create "project_a")
PROJECT_B_ID=$(get_id openstack project create "project_b")
ROLE_ADMIN_ID=$(get_id openstack role show admin)
ROLE_CREATOR_ID=$(get_id openstack role create "creator")
ROLE_OBSERVER_ID=$(get_id openstack role create "observer")
ROLE_AUDIT_ID=$(get_id openstack role create "audit")
#
# Setup RBAC Admin of Project A
#
USER_ID=$(get_id openstack user create \
--password "$PASSWORD" \
--email "admin_a@example.net" \
"project_a_admin")
openstack role add \
--user "$USER_ID" \
--project "$PROJECT_A_ID" \
"$ROLE_ADMIN_ID"
#
# Setup RBAC Creator of Project A
#
USER_ID=$(get_id openstack user create \
--password "$PASSWORD" \
--email "creator_a@example.net" \
"project_a_creator")
openstack role add \
--user "$USER_ID" \
--project "$PROJECT_A_ID" \
"$ROLE_CREATOR_ID"
# Adding second creator user in project_a
USER_ID=$(openstack user create \
--password "$PASSWORD" \
--email "creator2_a@example.net" \
"project_a_creator_2" -f value -c id)
openstack role add \
--user "$USER_ID" \
--project "$PROJECT_A_ID" \
"$ROLE_CREATOR_ID"
#
# Setup RBAC Observer of Project A
#
USER_ID=$(get_id openstack user create \
--password "$PASSWORD" \
--email "observer_a@example.net" \
"project_a_observer")
openstack role add \
--user "$USER_ID" \
--project "$PROJECT_A_ID" \
"$ROLE_OBSERVER_ID"
#
# Setup RBAC Auditor of Project A
#
USER_ID=$(get_id openstack user create \
--password "$PASSWORD" \
--email "auditor_a@example.net" \
"project_a_auditor")
openstack role add \
--user "$USER_ID" \
--project "$PROJECT_A_ID" \
"$ROLE_AUDIT_ID"
#
# Setup RBAC Admin of Project B
#
USER_ID=$(get_id openstack user create \
--password "$PASSWORD" \
--email "admin_b@example.net" \
"project_b_admin")
openstack role add \
--user "$USER_ID" \
--project "$PROJECT_B_ID" \
"$ROLE_ADMIN_ID"
#
# Setup RBAC Creator of Project B
#
USER_ID=$(get_id openstack user create \
--password "$PASSWORD" \
--email "creator_b@example.net" \
"project_b_creator")
openstack role add \
--user "$USER_ID" \
--project "$PROJECT_B_ID" \
"$ROLE_CREATOR_ID"
#
# Setup RBAC Observer of Project B
#
USER_ID=$(get_id openstack user create \
--password "$PASSWORD" \
--email "observer_b@example.net" \
"project_b_observer")
openstack role add \
--user "$USER_ID" \
--project "$PROJECT_B_ID" \
"$ROLE_OBSERVER_ID"
#
# Setup RBAC auditor of Project B
#
USER_ID=$(get_id openstack user create \
--password "$PASSWORD" \
--email "auditor_b@example.net" \
"project_b_auditor")
openstack role add \
--user "$USER_ID" \
--project "$PROJECT_B_ID" \
"$ROLE_AUDIT_ID"
}
# PyKMIP functions
# ----------------
# install_pykmip - install the PyKMIP python module
# create keys and certificate for server
function install_pykmip {
pip_install 'pykmip'
if is_service_enabled pykmip-server; then
[ ! -d ${PYKMIP_CONF_DIR} ] && sudo mkdir -p ${PYKMIP_CONF_DIR}
sudo chown ${USER} ${PYKMIP_CONF_DIR}
[ ! -d ${PYKMIP_LOG_DIR} ] && sudo mkdir -p ${PYKMIP_LOG_DIR}
sudo chown ${USER} ${PYKMIP_LOG_DIR}
init_CA
if [ ! -e ${PYKMIP_SERVER_KEY} ]; then
make_cert ${INT_CA_DIR} 'pykmip-server' 'pykmip-server'
chmod 400 ${PYKMIP_SERVER_KEY}
fi
if [ ! -e ${PYKMIP_CLIENT_KEY} ]; then
make_cert ${INT_CA_DIR} 'pykmip-client' 'pykmip-client'
chmod 400 ${PYKMIP_CLIENT_KEY}
fi
if [ ! -e ${PYKMIP_CONF} ]; then
cat > ${PYKMIP_CONF} <<EOF
[server]
hostname=127.0.0.1
port=5696
certificate_path=${PYKMIP_SERVER_CERT}
key_path=${PYKMIP_SERVER_KEY}
ca_path=${PYKMIP_CA_PATH}
auth_suite=TLS1.2
EOF
fi
fi
}
# configure_pykmip - enable KMIP plugin and configure
function configure_pykmip {
iniset $BARBICAN_CONF secretstore enabled_secretstore_plugins kmip_plugin
iniset $BARBICAN_CONF kmip_plugin username demo
iniset $BARBICAN_CONF kmip_plugin password secretpassword
iniset $BARBICAN_CONF kmip_plugin keyfile ${PYKMIP_CLIENT_KEY}
iniset $BARBICAN_CONF kmip_plugin certfile ${PYKMIP_CLIENT_CERT}
iniset $BARBICAN_CONF kmip_plugin ca_certs ${PYKMIP_CA_PATH}
}
# start_pykmip - start the PyKMIP server
function start_pykmip {
run_process pykmip-server "$BARBICAN_BIN_DIR/pykmip-server -f ${PYKMIP_CONF} -l ${PYKMIP_LOG_DIR}/pykmip-devstack.log"
}
# Dogtag functions
# ----------------
function install_389_directory_server {
# Make sure that 127.0.0.1 resolves to localhost.localdomain (fqdn)
sudo sed -i 's/127.0.0.1[ \t]*localhost localhost.localdomain/127.0.0.1\tlocalhost.localdomain localhost/' /etc/hosts
sudo mkdir -p /etc/389-ds
dscreate create-template ds.tmp
sed -e 's/;root_password = .*/root_password = PASSWORD/g' \
-e 's/;full_machine_name = .*/full_machine_name = localhost.localdomain/g' \
-e 's/;instance_name =.*/instance_name = pki-tomcat/g' \
ds.tmp > ds.inf
rm ds.tmp
sudo mv ds.inf /etc/389-ds/ds.inf
sudo dscreate from-file /etc/389-ds/ds.inf
}
function install_dogtag_ca {
sudo mkdir -p /etc/dogtag
cat > .tmp.ca.cfg <<EOF
[CA]
pki_admin_email=caadmin@example.com
pki_admin_name=caadmin
pki_admin_nickname=caadmin
pki_admin_password=PASSWORD
pki_admin_uid=caadmin
pki_backup_password=PASSWORD
pki_client_database_password=PASSWORD
pki_client_database_purge=False
pki_client_pkcs12_password=PASSWORD
pki_clone_pkcs12_password=PASSWORD
pki_ds_base_dn=dc=ca,dc=example,dc=com
pki_ds_database=ca
pki_ds_password=PASSWORD
pki_hostname=localhost
pki_security_domain_name=EXAMPLE
pki_token_password=PASSWORD
pki_https_port=8373
pki_http_port=8370
pki_ajp_port=8379
pki_tomcat_server_port=8375
EOF
sudo mv .tmp.ca.cfg /etc/dogtag/ca.cfg
sudo pkispawn -v -f /etc/dogtag/ca.cfg -s CA
}
function wait_for_ca {
while true; do
# If the sleep command is executed "as-is", the subprocess that it
# executes will trigger the "exit_trap" and will cause this script to
# fail. To avoid this, we run the sleep command inside this sub-shell,
# so the signal will not be caught in this process.
ca_running=$(sleep 2 && curl -s -k https://localhost:8373/ca/admin/ca/getStatus | grep -c running)
if [[ $ca_running == 1 ]]; then
break
fi
done
}
function install_dogtag_kra {
sudo mkdir -p /etc/dogtag
# Even though we are using localhost.localdomain, the server certificate by
# default will get the real host name for the server. So we need to
# properly configure the KRA to try to communicate with the real host name
# instead of the localhost.
cat > .tmp.kra.cfg <<EOF
[KRA]
pki_admin_cert_file=/root/.dogtag/pki-tomcat/ca_admin.cert
pki_admin_email=kraadmin@example.com
pki_admin_name=kraadmin
pki_admin_nickname=kraadmin
pki_admin_password=PASSWORD
pki_admin_uid=kraadmin
pki_backup_password=PASSWORD
pki_client_database_password=PASSWORD
pki_client_database_purge=False
pki_client_pkcs12_password=PASSWORD
pki_clone_pkcs12_password=PASSWORD
pki_ds_base_dn=dc=kra,dc=example,dc=com
pki_ds_database=kra
pki_ds_password=PASSWORD
pki_hostname=localhost
pki_security_domain_name=EXAMPLE
pki_security_domain_user=caadmin
pki_security_domain_password=PASSWORD
pki_token_password=PASSWORD
pki_https_port=8373
pki_http_port=8370
pki_ajp_port=8379
pki_tomcat_server_port=8375
pki_security_domain_hostname=localhost
pki_security_domain_https_port=8373
EOF
sudo mv .tmp.kra.cfg /etc/dogtag/kra.cfg
sudo pkispawn -v -f /etc/dogtag/kra.cfg -s KRA
}
function install_dogtag_plugin_dependencies {
install_package nss-devel 389-ds-base dogtag-pki
}
function install_dogtag_components {
install_dogtag_plugin_dependencies
install_389_directory_server
install_dogtag_ca
wait_for_ca
install_dogtag_kra
}
# Vault functions
# ----------------
function install_vault {
# Install vault if needed
if [[ ! -x "$(command -v vault)" ]]; then
wget https://releases.hashicorp.com/vault/1.3.0/vault_1.3.0_linux_amd64.zip
unzip vault_1.3.0_linux_amd64.zip
sudo mv vault /usr/bin
fi
install_package screen
TOKEN_ID_FILE="${BARBICAN_DIR}/vault_root_token_id"
local session_name="barbican_vault"
# Clean up first before starting new screen session
existing_ses=$(screen -ls | grep ${session_name} | awk '{print $1}')
if [[ -n "${existing_ses}" ]]; then
screen -S ${existing_ses} -X quit
fi
rm -f ${TOKEN_ID_FILE} vault.log
screen -dmS ${session_name}
screen -S ${session_name} -p bash -X stuff 'vault server -dev 2>&1 >vault.log\n'
# get the root_token_id, use tempfile for counter
touch $TOKEN_ID_FILE
COUNTER=0
while [ ! -s $TOKEN_ID_FILE ] && [ "$COUNTER" -lt "20" ]
do
sleep 2
awk '/Root Token:/ {print $3}' vault.log > $TOKEN_ID_FILE
COUNTER=$[COUNTER + 1]
done
if [ ! -s $TOKEN_ID_FILE ]; then
echo "Wah! Need to throw an error code here!"
fi
export VAULT_ADDR="http://127.0.0.1:8200"
# Enable kv version 1
vault secrets disable secret/
vault secrets enable -version=1 -path=secret -description "kv version 1" kv
#debug code follows:
vault status
vault kv put secret/hello foo=world
vault kv get secret/hello
vault kv delete secret/hello
}
function configure_vault_plugin {
root_token_id=`cat ${BARBICAN_DIR}/vault_root_token_id`
iniset $BARBICAN_CONF secretstore enabled_secretstore_plugins vault_plugin
iniset $BARBICAN_CONF vault_plugin root_token_id $root_token_id
iniset $BARBICAN_CONF vault_plugin vault_url "http://127.0.0.1:8200"
iniset $BARBICAN_CONF vault_plugin use_ssl "false"
}
# Restore xtrace
$XTRACE