From bb24370a10f7dd7f0490edba4add1e3c879828c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20L=C3=B3pez-Malla=20Matute?= Date: Tue, 25 Jul 2017 09:16:07 +0200 Subject: [PATCH] added dynamic authentication (#38) --- DockerfileHistory | 2 +- docker/historyServer/entrypoint.sh | 28 +- docker/historyServer/kms_utils.sh | 438 ----------------------------- 3 files changed, 20 insertions(+), 448 deletions(-) delete mode 100755 docker/historyServer/kms_utils.sh diff --git a/DockerfileHistory b/DockerfileHistory index b48ba7e166a2f..5dcac011f3108 100644 --- a/DockerfileHistory +++ b/DockerfileHistory @@ -7,6 +7,7 @@ RUN yum -y update \ && yum -y install java-1.8.0-openjdk curl wget\ && yum -y clean all \ && wget https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 \ + && curl -o /root/kms_utils-0.2.1.sh http://sodio.stratio.com/repository/paas/kms_utils/0.2.1/kms_utils-0.2.1.sh \ && mv jq-linux64 /usr/local/bin/jq \ && chmod 755 /usr/local/bin/jq \ && ln -s /usr/local/bin/jq /usr/bin/ \ @@ -18,7 +19,6 @@ COPY dist /opt/sds/spark COPY docker/historyServer/entrypoint.sh / COPY docker/historyServer/commons.sh / -COPY docker/historyServer/kms_utils.sh / ENTRYPOINT ["/usr/local/bin/dumb-init", "/entrypoint.sh"] diff --git a/docker/historyServer/entrypoint.sh b/docker/historyServer/entrypoint.sh index 4a50a4a98cb28..93e88ab2bc22b 100755 --- a/docker/historyServer/entrypoint.sh +++ b/docker/historyServer/entrypoint.sh @@ -1,6 +1,7 @@ #!/bin/bash -source kms_utils.sh +source /root/kms_utils-0.2.1.sh + source commons.sh # Create krb5.conf file @@ -28,10 +29,14 @@ EOM function main() { HDFS_HADOOP_SECURITY_AUTH_TO_LOCAL=${HDFS_HADOOP_SECURITY_AUTH_TO_LOCAL:=${auth_to_local_value}} VAULT_PORT=${VAULT_PORT:=8200} - VAULT_TOKEN=${VAULT_TOKEN:=1111111-2222-3333-4444-5555555555555} + VAULT_HOSTS=$VAULT_HOST + SERVICE_ID=$APP_NAME + INSTANCE=$APP_NAME + VAULT_URI="$VAULT_PROTOCOL://$VAULT_HOSTS:$VAULT_PORT" + SPARK_HOME=/opt/sds/spark FQDN=${HISTORY_SERVER_FQDN:="history-server"} - INSTANCE=${HISTORY_SERVER_FQDN:=$FQDN} + INSTANCE=${HISTORY_SERVER_FQDN:="history-server"} mkdir -p $HADOOP_CONF_DIR @@ -47,14 +52,19 @@ function main() { if [[ "$HDFS_KRB_ENABLE" == "true" ]] then - SPARK_KEYTAB_PATH="/etc/sds/spark/security" - getKrb userland $INSTANCE $FQDN "$SPARK_KEYTAB_PATH" HISTORY_SERVER_PRINCIPAL_NAME - generate_krb-conf "${KERBEROS_REALM}" "${KERBEROS_KDC_HOST}" "${KERBEROS_KADMIN_HOST}" - mv "/tmp/krb5.conf.tmp" "/etc/krb5.conf" - SPARK_HISTORY_OPTS="-Dspark.history.kerberos.principal=${HISTORY_SERVER_PRINCIPAL_NAME} -Dspark.history.kerberos.keytab=${SPARK_KEYTAB_PATH}/${FQDN}.keytab -Dspark.history.kerberos.enabled=true ${SPARK_HISTORY_OPTS}" + if [ ! -z "$VAULT_ROLE_ID" ]; then + echo "Vault role id proved, signing in" + login + fi + SPARK_KEYTAB_PATH="/etc/sds/spark/security" + getKrb userland $INSTANCE $FQDN "$SPARK_KEYTAB_PATH" HISTORY_SERVER_PRINCIPAL_NAME + + generate_krb-conf "${KERBEROS_REALM}" "${KERBEROS_KDC_HOST}" "${KERBEROS_KADMIN_HOST}" + mv "/tmp/krb5.conf.tmp" "/etc/krb5.conf" + SPARK_HISTORY_OPTS="-Dspark.history.kerberos.principal=${HISTORY_SERVER_PRINCIPAL_NAME} -Dspark.history.kerberos.keytab=${SPARK_KEYTAB_PATH}/${FQDN}.keytab -Dspark.history.kerberos.enabled=true ${SPARK_HISTORY_OPTS}" else - echo 'HDFS SECURITY IS NOT ENABLE' + echo 'HDFS SECURITY IS NOT ENABLE' fi generate_core-site "${HDFS_FS_DEFAULTFS}" "${HDFS_HADOOP_SECURITY_AUTHORIZATION}" "${HDFS_HADOOP_SECURITY_AUTHENTICATION}" "${HDFS_HADOOP_SECURITY_AUTH_TO_LOCAL}" diff --git a/docker/historyServer/kms_utils.sh b/docker/historyServer/kms_utils.sh deleted file mode 100755 index fa7aaabdb19de..0000000000000 --- a/docker/historyServer/kms_utils.sh +++ /dev/null @@ -1,438 +0,0 @@ -#!/bin/bash - -################################################################################ -######## Stratio Inc. All Rights Reserved ######## -######## author: Carlos Gomez ######## -################################################################################ - -#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#@@@@ Note all this functions expects the following vars as globals @@@@@@@ -#@@@@ - VAULT_HOSTS [array] @@@@@@@ -#@@@@ - VAULT_PORT [int] @@@@@@@ -#@@@@ - VAULT_TOKEN [string] @@@@@@@ -#@@@@ @@@@@@@ -#@@@@ To read an array from comma separted string @@@@@@@ -#@@@@ IFS=',' read -r -a VAULT_HOSTS <<< "$STRING_VAULT_HOST" @@@@@@@ -#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -# -# Get secret -# INPUTS: -# 1: cluster [ca-trust, gosec, dcs, userland] -# 2: instance -# 3: secret -# OUTPUTS: -# populate ENV VARS as <$INSTANCE>_<$SECRET>_=VALUE -# -function getPass() { - local cluster=$1 - local instance=$2 - local secret=$3 - local rawdata='' - local data='' - local key='' - local value='' - declare -A secret_map - - OLD_IFS=$IFS - result=$(_get_from_vault "/$cluster/passwords/$instance/$secret") - IFS=',' read -r status_code rawdata <<< "$result" - if [[ $status_code == 200 ]]; - then - data=$(echo "$rawdata" | jq -cMSr '.data') - while IFS='=' read -r key value - do - secret_map[$key]="$value" - done < <(echo "$data" | jq -r "to_entries|map(\"\(.key)=\(.value)\")|.[]") - - underscore_instance=${instance//[.-]/_} - underscore_secret=${secret//[.-]/_} - for key in "${!secret_map[@]}" - do - underscore_key=${key//[.-]/_} - export "${underscore_instance^^}"_"${underscore_secret^^}"_"${underscore_key^^}"="${secret_map[$key]}" - _log "<< getpass - $instance $secret obtained succesfully" - done - else - _log "<< getpass - error -1 requesting $instance $secret" - return 1 - fi - - IFS=$OLD_IFS - return 0 -} - -# -# Get principal and b64 encoded keytab -# INPUTS: -# 1 cluster -# 2 instance -# 3 fqdn or name (in case principal doesn't have fqdn) -# 4 path to save file(s) $fqdn.keytab -# 5 variable to store principal -# OUTPUTS: -# 1 STDOUT << 0 if everything was ok -# STDOUT << error code or HTTP status code if there was an error -# 2 $4/$3.keytab -# -function getKrb() { - local cluster=$1 - local instance=$2 - local fqdn=$3 - local store_path=$4 - local principal=$5 - local krb_credentials='' - local encoded_ktab='' - - #TODO: extract principal(s) from keytab - vault_path=$cluster/kerberos/$instance - - # ensure $store_path exists - mkdir -p "$store_path" - OLD_IFS=$IFS - - result=$(_get_from_vault "${vault_path}") - IFS=',' read -r status_code krb_credentials <<< "$result" - if [[ $status_code == 200 ]]; then - json_princ_key="$fqdn"_principal - json_ktab_key="$fqdn"_keytab - local principal_value - principal_value=$(echo "$krb_credentials" | jq -cMSr --arg fqdn "$json_princ_key" '.data[$fqdn]') - eval "$principal=$principal_value" - encoded_ktab=$(echo "$krb_credentials" | jq -cMSr --arg fqdn "$json_ktab_key" '.data[$fqdn]') - _log "<< getkrb - credentials to $fqdn downloaded" - - echo "$encoded_ktab" | base64 -d > "$store_path/$fqdn.keytab" - if [[ $? == 0 ]]; then - _log ">> getkrb - keytab saved to $principal in $store_path" - else - _log ">> getkrb - error 1 saving keytab to $store_path" - return 1 - fi - else - _log "<< getkrb - error $status_code downloading kerberos credentials to $fqdn" - return "$status_code" - fi - - IFS=$OLD_IFS - return 0 -} - -# -# Get public certificate and private key -# INPUTS: -# 1 cluster -# 2 instance -# 3 fqdn or name (in case principal doesn't have fqdn) -# 4 ca-boundle format: JKS or P12 or PEM -# 5 path to save file(s) $fqdn.{jks|p12|pem.key} -# OUTPUTS: -# 1 STDOUT << 0 if everything was ok -# STDOUT << error code or HTTP status code if there was an error -# 2 $5/$3.{jks|p12|pem.key} -# -function getCert() { - local cluster=$1 - local instance=$2 - local fqdn=$3 - local o_format=$4 - local store_path=$5 - local result='' - local certificates='' - local public_key='' - local private_key='' - local temp_pem_pub='' - local temp_pem_priv='' - local status_code='' - - vault_path=$cluster/certificates/$instance - - temp_pem_pub=$(mktemp -p /dev/shm) - temp_pem_priv=$(mktemp -p /dev/shm) - - # ensure $store_path exists - mkdir -p "$store_path" - - OLD_IFS=$IFS - - result=$(_get_from_vault "${vault_path}") - IFS=',' read -r status_code certificates <<< "$result" - if [[ "$status_code" == 200 ]]; then - json_crt_key="$fqdn"_crt - json_key_key="$fqdn"_key - public_key=$(echo "$certificates" | jq -cMSr --arg fqdn "$json_crt_key" '.data[$fqdn]') - private_key=$(echo "$certificates" | jq -cMSr --arg fqdn "$json_key_key" '.data[$fqdn]') - echo "$public_key" | sed \ - -e 's/-----BEGIN CERTIFICATE-----/-----BEGIN CERTIFICATE-----\n/g' \ - -e 's/-----END CERTIFICATE-----/\n-----END CERTIFICATE-----/g' \ - -e 's/-----END CERTIFICATE----------BEGIN CERTIFICATE-----/-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----/g'> "$temp_pem_pub" - if [[ $? == 0 ]]; then - _log ">> getcertificate - public key $fqdn downloaded" - else - _log ">> getcertificate - error 2 while $fqdn was downloaded" - rm -rf "$temp_pem_pub" \ - rm -rf "$temp_pem_priv" \ - return 2 - fi - - echo "$private_key" | sed \ - -e 's/-----BEGIN RSA PRIVATE KEY-----/-----BEGIN RSA PRIVATE KEY-----\n/g' \ - -e 's/-----END RSA PRIVATE KEY-----/\n-----END RSA PRIVATE KEY-----/g' > "$temp_pem_priv" - if [[ $? == 0 ]]; then - _log ">> getcertificate - private key $fqdn downloaded" - else - _log ">> getcertificate - error 3 while $fqdn was downloaded" - rm -rf "$temp_pem_pub" \ - rm -rf "$temp_pem_priv" \ - return 3 - fi - - case $o_format in - PEM) - cp -f "$temp_pem_pub" "$store_path/$fqdn.pem" - cp -f "$temp_pem_priv" "$store_path/$fqdn.key" - ;; - P12|JKS) - p12_temp=$(mktemp -p /dev/shm) - getPass "$cluster" "$instance" keystore - underscore_instance=${instance//[-.]/_} - ptr_password="${underscore_instance^^}_KEYSTORE_PASS" - - openssl pkcs12 -export \ - -inkey "$temp_pem_priv" \ - -in "$temp_pem_pub" \ - -passout pass:"${!ptr_password}" \ - -out "$p12_temp" - if [[ $? == 0 ]]; then - _log ">> getcertificate - P12 created" - else - _log ">> getcertificate - error 4 creating P12" - rm -rf "$p12_temp" - rm -rf "$temp_pem_pub" - rm -rf "$temp_pem_priv" - return 4 - fi - - if [ "$o_format" == "P12" ]; then - cp "$p12_temp" "$store_path/$fqdn.p12" - else - keytool -noprompt -importkeystore -srckeystore "$p12_temp" \ - -srcstorepass "${!ptr_password}" \ - -srcstoretype PKCS12 \ - -destkeystore "$store_path/$fqdn.jks" \ - -deststorepass "${!ptr_password}" 2>/dev/null - if [[ $? == 0 ]]; then - _log ">> getcertificate - JKS created" - else - _log ">> getcertificate - error 5 creating JKS" - rm -rf "$p12_temp" - rm -rf "$temp_pem_pub" - rm -rf "$temp_pem_priv" - return 5 - fi - fi - rm -rf "$p12_temp" - ;; - *) - _log "<< getcertificate - error 6 Invalid keystore format" - return 6 - esac - - fi - - rm -rf "$temp_pem_pub" - rm -rf "$temp_pem_priv" - IFS=$OLD_IFS - return 0 -} - - -# -# Get CA public certificates -# INPUTS: -# 1 path to directory to save ca-bundle.{pem,jks} -# 2 ca-bundle format: JKS or PEM -# 3 optional file to store ca-bundle -# 4 optional cluster to find keystore password -# 5 optional instance to find keystore password -# OUTPUTS: -# 1 STDOUT << 0 if everything was ok -# STDOUT << HTTP status code if there was an error -# -function getCAbundle() { - local store_path=$1 - local format=$2 - local bundle_file=${3:-"ca-bundle"} - local cluster=${4:-"ca-trust"} - local instance=${5:-"default"} - declare -a list_ca - #local kstore_pass='' - local result='' - local status_code='' - - # get CAs list from ca-trust/certificates - # for each ca append to $store_path/ca-bundle.pem - # if format = jks - # add CA to JKS - # return with exit code - - # ensure $store_path exists - mkdir -p "$store_path" - - OLD_IFS=$IFS - - result=$(_get_from_vault "ca-trust/certificates?list=true") - IFS=',' read -r status_code list <<< "$result" - if [[ $status_code == 200 ]]; then - IFS=',' read -r -a list_ca <<< "$(echo "$list" | jq -cMSr '.data .keys' | tr -d '[' |tr -d ']' | tr -d '"')" - - temp_pem=$(mktemp -p /dev/shm) - formated_pem=$(mktemp -p /dev/shm) - for ca in "${list_ca[@]}"; - do - result=$(_get_from_vault ca-trust/certificates/"$ca") - IFS=',' read -r status_code ca_pub_key <<< "$result" - if [[ $status_code == 200 ]]; then - - json_crt="$fqdn"_crt - ca_public_key=$(echo "$ca_pub_key" | jq -cMSr --arg fqdn "$json_crt" '.data[$fqdn]') - - echo "$ca_pub_key" | jq -cMSr ".data .${ca}_crt" | sed \ - -e 's/-----BEGIN CERTIFICATE-----/-----BEGIN CERTIFICATE-----\n/g' \ - -e 's/-----END CERTIFICATE-----/\n-----END CERTIFICATE-----/g' \ - -e 's/-----END CERTIFICATE----------BEGIN CERTIFICATE-----/-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----/g'> "$formated_pem" - - if [[ "$format" == "PEM" ]]; then - if [ "$bundle_file" == "ca-bundle" ] - then - bundle_file=${bundle_file}.pem - fi - cat "$formated_pem" >> "$store_path/$bundle_file" - if [[ $? == 0 ]]; then - _log ">> getcabundle - $ca saved to $store_path/$bundle_file" - else - _log ">> getcabundle - error 252 while saving $ca to $store_path/$bundle_file" - return 252 - fi - - elif [[ "$format" == "JKS" ]]; then - if [ "$bundle_file" == "ca-bundle" ] - then - bundle_file=${bundle_file}.jks - fi - getPass "$cluster" "$instance" keystore - upcase_instance=${instance^^} - ptr_password="${upcase_instance//[.-]/_}_KEYSTORE_PASS" - keytool -import -noprompt -alias "$ca" -keystore "$store_path/$bundle_file" \ - -storepass "${!ptr_password}" -file "$formated_pem" >/dev/null 2>&1 - if [[ $? == 0 ]]; then - _log ">> getcabundle - $ca saved to $store_path/$bundle_file" - else - _log ">> getcabundle - error 3 while saving $ca to $store_path/$bundle_file" - return 3 - fi - fi - - > "$formated_pem" - > "$temp_pem" - else - _log "<< getcabundle - error 2 requesting $ca" - rm -f "$temp_pem" - rm -f "$formated_pem" - echo 2 - return 2 - fi - done - - rm -f "$temp_pem" - rm -f "$formated_pem" - return 0 - else - _log "<< getcabundle - error 1 requesting CA list from /ca-trust/certificates" - echo 1 - return 1 - fi - IFS=$OLD_IFS - return 0 -} - - -# -# Send a HTTP GET method to vault server -# INPUTS: -# vault's path -# OUTPUTS: -# STDOUT << http_code,data -# -function _get_from_vault() { - local path=$1 - local vault_hosts=$VAULT_HOSTS - local vault_port=$VAULT_PORT - local vault_token=$VAULT_TOKEN - local response='' - local data='' - local status_code=-1 - local curl_opts="-fLs --tlsv1.2 -k" - #local curl_opts='-sLf' - - for Vhost in "${vault_hosts[@]}" - do - response=$(curl $curl_opts -w "%{response_code}" -H "X-Vault-Token:$vault_token" \ - "https://$Vhost:$vault_port/v1/$path") - data=$(echo "$response" |head -1 ) - status_code=$(echo "$response" | tail -1) - if [[ $status_code == 200 ]];then - echo "$status_code,$data" - return 0 - fi - done - echo "$status_code, error getting data from $path" - return 1 -} - - -# -# Change key's value to file -# INPUTS: -# 1 configuration key -# 2 configuration value -# 3 configuration file -# 4 [mod] substitute till the end of the line -# OUTPUTS: -# -# Supported key formats: -# key1= | key2 = | key3: | key4: | "key5": "" | "key6": "", | key7 value -# -function key_substitution() { - local key=$1 - local value=$2 - local file=$3 - local eol=$4 - - if [[ $eol ]]; then - sed -ri "s#(\"|)($key)(\s|\"|)(=|:| )(\s|)(\"|)(\w+).*#\1\2\3\4\5\6$value#g" "$file" - else - sed -ri "s#(\"|)($key)(\s|\"|)(=|:| )(\s|)(\"|)(\w+)(\"|)(,|\s|)#\1\2\3\4\5\6$value\8\9#g" "$file" - fi - if [[ $? == 0 ]]; then - _log "key_substitution - $key configured in $file" - else - _log "key_substitution - error 1 something went wrong when $key was configured in $file" - return 1 - fi - return 0 -} - -function _log() { - local message=$1 - - if [[ "$JOURNAL_LOG" == "true" ]]; then - echo "$(date +'%b %d %R:%S.%N') $message" | systemd-cat -t vault - else - echo -e "$(date +'%b %d %R:%S.%N') [vault-utils] $message\n" | tee -a "$PWD/vault-utils.log" - fi -} - -#if [[ $(systemd-cat 1>&2 2>/dev/null && echo $?) -eq 0 ]]; then -# JOURNAL_LOG=false -#fi -JOURNAL_LOG=false