Comment masquer un mot de passe dans les scripts Shell? Il existe un certain nombre de scripts qui accèdent à la base de données. Si nous ouvrons le script, d'autres connaissent également le nom d'utilisateur et le mot de passe. Donc, si quelqu'un sait comment se cacher, faites-le moi savoir.
J'ai un moyen: placer le mot de passe dans un fichier et le rendre caché et personne ne va accéder au fichier (modifier les autorisations et utiliser le fichier dans le script tout en accédant à la base de données).
First, comme plusieurs personnes l'ont déjà dit, il est essentiel de conserver les informations d'identification distinctes du script. (En plus d'une sécurité accrue, cela signifie également que vous pouvez réutiliser le même script pour plusieurs systèmes avec des informations d'identification différentes.)
Second, vous devez considérer non seulement la sécurité des informations d'identification, mais également l'impact si/quand ces informations d'identification sont compromises. Vous ne devez pas avoir un seul mot de passe pour tous les accès à la base de données, vous devez avoir des informations d'identification différentes avec différents niveaux d'accès. Vous pouvez, par exemple, avoir un utilisateur de base de données qui a la possibilité d'effectuer une recherche dans la base de données - cet utilisateur doit avoir un accès en lecture seule. Un autre utilisateur peut être autorisé à insérer de nouveaux enregistrements, mais pas à les supprimer. Un troisième peut être autorisé à supprimer des enregistrements.
En plus de restreindre les autorisations pour chaque compte, vous devez également restreindre la provenance de chaque compte. Par exemple, le compte utilisé par votre serveur Web ne doit pas être autorisé à se connecter à partir d'une autre adresse IP que celle du serveur Web. Un compte avec des autorisations root complètes sur la base de données doit en effet être très restreint en termes de provenance et ne doit jamais être utilisé autrement qu'interactivement. Pensez également à utiliser des procédures stockées dans la base de données pour restreindre exactement ce qui peut être fait par chaque compte.
Ces restrictions doivent être implémentées du côté serveur de base de données du système, de sorte que même si le côté client est compromis, les restrictions ne peuvent pas être modifiées. (Et, évidemment, le serveur DB doit être protégé avec des pare-feu, etc. en plus de la configuration DB ...)
Dans le cas d'un compte DB qui n'est autorisé qu'à un accès limité en lecture seule, et uniquement à partir d'une adresse IP particulière, vous n'aurez peut-être pas besoin d'autres informations d'identification que cela, selon la sensibilité des données et la sécurité de l'hôte du script est en cours d'exécution. Un exemple peut être un formulaire de recherche sur votre site Web, qui peut être exécuté avec un utilisateur qui est uniquement autorisé à utiliser une procédure stockée qui extrait uniquement les informations qui seront présentées sur la page Web. Dans ce cas, l'ajout d'un mot de passe ne confère pas vraiment de sécurité supplémentaire, car ces informations sont déjà censées être publiques, et l'utilisateur ne peut accéder à aucune autre donnée qui serait plus sensible.
Assurez-vous également que la connexion à la base de données est établie à l'aide de TLS, ou que quiconque écoute sur le réseau peut obtenir vos informations d'identification.
Troisième, réfléchissez au type d'informations d'identification à utiliser. Les mots de passe ne sont qu'une forme et ne sont pas les plus sécurisés. Vous pouvez à la place utiliser une certaine forme de paire de clés publique/privée, ou AD/PAM ou similaire.
Quatrième, considérez les conditions dans lesquelles le script sera exécuté:
S'il est exécuté de manière interactive, vous devez entrer le mot de passe ou le mot de passe de la clé privée ou de la clé privée, ou être connecté avec un ticket Kerberos valide, lorsque vous l'exécutez - en d'autres termes, le script doit obtenir son informations d'identification directement auprès de vous au moment où vous l'exécutez, au lieu de les lire à partir d'un fichier.
S'il est exécuté à partir d'un serveur Web, envisagez de configurer les informations d'identification au moment où vous démarrez le serveur Web. Un bon exemple ici est les certificats SSL - ils ont un certificat public et une clé privée, et la clé privée a un mot de passe. Vous pouvez stocker la clé privée sur le serveur Web, mais vous devez toujours y saisir le mot de passe lorsque vous démarrez Apache. Vous pouvez également disposer des informations d'identification sur un type de matériel, comme une carte physique ou un HSM, qui peut être supprimé ou verrouillé une fois le serveur démarré. (Bien sûr, l'inconvénient de cette méthode est que le serveur ne peut pas redémarrer seul si quelque chose se produit. Je préférerais cela au risque de compromettre mon système, mais votre kilométrage peut varier ...)
Si le script est exécuté à partir de cron, c'est la partie difficile. Vous ne voulez pas que les informations d'identification se trouvent n'importe où sur votre système où quelqu'un puisse y accéder - mais vous voulez les faire traîner afin que votre script puisse y accéder, non? Eh bien, pas tout à fait raison. Considérez exactement ce que fait le script. De quelles autorisations a-t-il besoin sur la base de données? Peut-il être restreint afin que cela n'ait pas d'importance si la mauvaise personne se connecte avec ces autorisations? Pouvez-vous plutôt exécuter le script directement sur le serveur de base de données auquel personne d'autre n'a accès, au lieu du serveur qui a d'autres utilisateurs? Si, pour une raison à laquelle je ne peux pas penser, vous devez absolument exécuter le script sur un serveur non sécurisé et le doit être capable de faire quelque chose de dangereux/destructeur ... c'est le bon moment pour repenser votre architecture.
Cinquième, si vous appréciez la sécurité de votre base de données, vous ne devriez pas exécuter ces scripts sur des serveurs auxquels d'autres personnes ont accès. Si quelqu'un est connecté sur votre système, il aura a la possibilité d'obtenir vos informations d'identification. Par exemple, dans le cas d'un serveur Web avec un certificat SSL, il existe au moins une possibilité théorique que quelqu'un puisse accéder à la racine et accéder à la zone de mémoire du processus httpd et extraire les informations d'identification. Il y a eu au moins un exploit ces derniers temps où cela pourrait être fait via SSL, sans même exiger que l'attaquant soit connecté.
Pensez également à utiliser SELinux ou apparmor ou tout ce qui est disponible pour votre système pour restreindre les utilisateurs qui peuvent faire quoi. Ils vous permettront d'interdire aux utilisateurs d'essayer même de se connecter à la base de données, même s'ils parviennent à accéder aux informations d'identification.
Si tout cela vous semble exagéré, et vous ne pouvez pas vous permettre ou n'avez pas le temps de le faire - alors, à mon avis (arrogant et élitiste), vous ne devriez rien stocker important ou sensible dans votre base de données. Et si vous ne stockez rien d'important ou de sensible, alors où vous stockez vos informations d'identification n'est pas important non plus - dans ce cas, pourquoi utiliser un mot de passe?
Enfin, si vous ne pouvez absolument pas éviter de stocker une sorte d'informations d'identification, vous pourriez avoir les informations d'identification en lecture seule et détenues par root et root pourrait accorder la propriété sur une base extrêmement temporaire lorsque demandé par un script (parce que votre script devrait pas être exécuté en tant que root sauf si cela est absolument nécessaire, et la connexion à une base de données ne le rend pas nécessaire). Mais ce n'est toujours pas une bonne idée.
Tout d'abord, s'il existe un moyen de changer les choses pour éviter d'avoir à stocker un mot de passe à l'intérieur ou à côté d'un script, vous devriez faire tous les efforts pour le faire. réponse de Jenny D contient beaucoup de bons conseils à cet effet.
Sinon, votre idée de placer le mot de passe dans un fichier séparé avec des autorisations restreintes est à peu près tout. Vous pouvez par exemple source ce fichier à partir du script principal:
. /usr/local/etc/secret-password-here
Vous pouvez également restreindre les autorisations du script principal afin que seules les personnes autorisées puissent l'exécuter, mais il est probablement préférable de faire comme vous le suggérez et de stocker uniquement le mot de passe lui-même dans un fichier restreint. De cette façon, vous pouvez permettre l'inspection du code lui-même (sans secrets sensibles), le contrôle de version et la copie autour du script plus facilement, etc ...
D'autres réponses ont abordé le comment, mais je considérerai le si. Selon le type de base de données auquel vos utilisateurs se connectent, vous disposez peut-être déjà d'un mécanisme approprié déjà utilisé par ces programmes clients, auquel cas assurez-vous de les utiliser (je pense à ~/.mysqlrc
ou ~/.pgpass
).
Si vous donnez à plusieurs utilisateurs la possibilité d'accéder à la base de données pour effectuer des requêtes spécifiques à l'aide d'un compte partagé, vous ne devriez probablement pas. Au lieu de cela, assurez-vous qu'ils ont des comptes sur la base de données et que ces comptes n'ont pas plus d'autorisations que nécessaire (probablement lire une grande partie de celui-ci et très peu d'accès en écriture). S'ils doivent effectuer des requêtes spécifiques sur certaines tables auxquelles ils ne pourraient pas accéder autrement, fournissez des procédures stockées avec SECURTY DEFINER
pour leur permettre de le faire.
Si rien de ce qui précède ne vous évite d'avoir à stocker des informations d'identification, alors lisez les autres réponses ici.
Votre idée de cacher le mot de passe dans un endroit inaccessible pourrait être OK selon les circonstances.
Si les informations sont séparées, cela signifie une simple modification du fichier, par exemple lors d'une révision de code avec un collègue ne va pas le montrer. Mais sachez que toute personne ayant accès à votre compte peut facilement trouver un tel fichier. J'ai utilisé un sous-répertoire de ~/.ssh
à de telles fins, pour la simple raison que ssh
se plaint si les droits d'accès pour ~/.ssh
ne sont pas assez restreints.
Il y a cependant d'autres choses que vous pouvez faire pour empêcher un tel coup d'œil du nom d'utilisateur et/ou des mots de passe.
Obfuscating: Si vous ne voulez pas que quelqu'un lise le nom d'utilisateur ou le mot de passe pendant que vous éditez un script, vous pouvez le mettre dans le texte mais pas en texte brut, mais obscurci. Si la version obscurcie est suffisamment longue pour empêcher sa mémorisation par quelqu'un qui la regarde, elle ne peut pas être connue même si la méthode et la clé de déchiffrement sont bien en vue. Bien sûr, cela serait encore contourné par une personne ayant accès à votre compte.
en utilisant GPG:
Un peu mieux, mais toujours pas une preuve complète contre les attaques de l'utilisateur root sur votre système, consiste à crypter les paires nom d'utilisateur/mot de passe dans un fichier public gpg
et à ce que le script récupère le contenu du fichier (possible, vous y invitant pour un mot de passe, s'il n'est pas mis en cache/expiré). J'utilise ggp-card pour que lorsque je laisse mon ordinateur portable autour mais que je retire la carte, aucun accès ne soit possible même si la broche serait toujours mise en cache. Au moins si je lance quelque chose 20 fois en quelques minutes, je ne dois fournir la broche qu'une seule fois.
La sécurité semble toujours inversement liée à la commodité (configuration et utilisation).
J'ai également rencontré ce problème. La réponse courte est de stocker le mot de passe séparément du script, puis de charger le script dans le mot de passe de l'environnement. Ce qui soulève la question de savoir comment le faire au mieux?
Idéalement, vous pourriez utiliser un service externe comme HashiCorp Vault pour le tirer dans l'environnement Shell; Cependant, Vault est une bête assez compliquée à configurer et dans de nombreux environnements d'entreprise, vous pouvez être limité par ce que vous pouvez installer et même le type de Shell que vous pourriez utiliser.
Pour cette raison, j'ai créé encpass.sh - Solution légère pour utiliser des mots de passe cryptés dans les scripts Shell qui vous permet de stocker des secrets dans un répertoire caché accessible uniquement par votre utilisateur. Il devrait fonctionner dans n'importe quel shell compatible POSIX et sa seule dépendance réelle est d'installer OpenSSL sur la boîte locale pour gérer le cryptage des secrets. Il vous suffit de l'inclure dans votre script et d'appeler la fonction "get_secret". Il a une licence MIT, vous pouvez donc l'utiliser dans un environnement d'entreprise. Mon entreprise, Plyint LLC , gère le script et publie des mises à jour de temps en temps. Je vais copier le code ci-dessous pour une visibilité facile.
#!/bin/sh
################################################################################
# Copyright (c) 2020 Plyint, LLC <[email protected]>. All Rights Reserved.
# This file is licensed under the MIT License (MIT).
# Please see LICENSE.txt for more information.
#
# DESCRIPTION:
# This script allows a user to encrypt a password (or any other secret) at
# runtime and then use it, decrypted, within a script. This prevents shoulder
# surfing passwords and avoids storing the password in plain text, which could
# inadvertently be sent to or discovered by an individual at a later date.
#
# This script generates an AES 256 bit symmetric key for each script (or user-
# defined bucket) that stores secrets. This key will then be used to encrypt
# all secrets for that script or bucket. encpass.sh sets up a directory
# (.encpass) under the user's home directory where keys and secrets will be
# stored.
#
# For further details, see README.md or run "./encpass ?" from the command line.
#
################################################################################
encpass_checks() {
if [ -n "$ENCPASS_CHECKS" ]; then
return
fi
if [ ! -x "$(command -v openssl)" ]; then
echo "Error: OpenSSL is not installed or not accessible in the current path." \
"Please install it and try again." >&2
exit 1
fi
if [ -z "$ENCPASS_HOME_DIR" ]; then
ENCPASS_HOME_DIR=$(encpass_get_abs_filename ~)/.encpass
fi
if [ ! -d "$ENCPASS_HOME_DIR" ]; then
mkdir -m 700 "$ENCPASS_HOME_DIR"
mkdir -m 700 "$ENCPASS_HOME_DIR/keys"
mkdir -m 700 "$ENCPASS_HOME_DIR/secrets"
fi
if [ "$(basename "$0")" != "encpass.sh" ]; then
encpass_include_init "$1" "$2"
fi
ENCPASS_CHECKS=1
}
# Initializations performed when the script is included by another script
encpass_include_init() {
if [ -n "$1" ] && [ -n "$2" ]; then
ENCPASS_BUCKET=$1
ENCPASS_SECRET_NAME=$2
Elif [ -n "$1" ]; then
ENCPASS_BUCKET=$(basename "$0")
ENCPASS_SECRET_NAME=$1
else
ENCPASS_BUCKET=$(basename "$0")
ENCPASS_SECRET_NAME="password"
fi
}
encpass_generate_private_key() {
ENCPASS_KEY_DIR="$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET"
if [ ! -d "$ENCPASS_KEY_DIR" ]; then
mkdir -m 700 "$ENCPASS_KEY_DIR"
fi
if [ ! -f "$ENCPASS_KEY_DIR/private.key" ]; then
(umask 0377 && printf "%s" "$(openssl Rand -hex 32)" >"$ENCPASS_KEY_DIR/private.key")
fi
}
encpass_get_private_key_abs_name() {
ENCPASS_PRIVATE_KEY_ABS_NAME="$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.key"
if [ "$1" != "nogenerate" ]; then
if [ ! -f "$ENCPASS_PRIVATE_KEY_ABS_NAME" ]; then
encpass_generate_private_key
fi
fi
}
encpass_get_secret_abs_name() {
ENCPASS_SECRET_ABS_NAME="$ENCPASS_HOME_DIR/secrets/$ENCPASS_BUCKET/$ENCPASS_SECRET_NAME.enc"
if [ "$3" != "nocreate" ]; then
if [ ! -f "$ENCPASS_SECRET_ABS_NAME" ]; then
set_secret "$1" "$2"
fi
fi
}
get_secret() {
encpass_checks "$1" "$2"
encpass_get_private_key_abs_name
encpass_get_secret_abs_name "$1" "$2"
encpass_decrypt_secret
}
set_secret() {
encpass_checks "$1" "$2"
if [ "$3" != "reuse" ] || { [ -z "$ENCPASS_SECRET_INPUT" ] && [ -z "$ENCPASS_CSECRET_INPUT" ]; }; then
echo "Enter $ENCPASS_SECRET_NAME:" >&2
stty -echo
read -r ENCPASS_SECRET_INPUT
stty echo
echo "Confirm $ENCPASS_SECRET_NAME:" >&2
stty -echo
read -r ENCPASS_CSECRET_INPUT
stty echo
fi
if [ "$ENCPASS_SECRET_INPUT" = "$ENCPASS_CSECRET_INPUT" ]; then
encpass_get_private_key_abs_name
ENCPASS_SECRET_DIR="$ENCPASS_HOME_DIR/secrets/$ENCPASS_BUCKET"
if [ ! -d "$ENCPASS_SECRET_DIR" ]; then
mkdir -m 700 "$ENCPASS_SECRET_DIR"
fi
printf "%s" "$(openssl Rand -hex 16)" >"$ENCPASS_SECRET_DIR/$ENCPASS_SECRET_NAME.enc"
ENCPASS_OPENSSL_IV="$(cat "$ENCPASS_SECRET_DIR/$ENCPASS_SECRET_NAME.enc")"
echo "$ENCPASS_SECRET_INPUT" | openssl enc -aes-256-cbc -e -a -iv \
"$ENCPASS_OPENSSL_IV" -K \
"$(cat "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.key")" 1>> \
"$ENCPASS_SECRET_DIR/$ENCPASS_SECRET_NAME.enc"
else
echo "Error: secrets do not match. Please try again." >&2
exit 1
fi
}
encpass_get_abs_filename() {
# $1 : relative filename
filename="$1"
parentdir="$(dirname "${filename}")"
if [ -d "${filename}" ]; then
cd "${filename}" && pwd
Elif [ -d "${parentdir}" ]; then
echo "$(cd "${parentdir}" && pwd)/$(basename "${filename}")"
fi
}
encpass_decrypt_secret() {
if [ -f "$ENCPASS_PRIVATE_KEY_ABS_NAME" ]; then
ENCPASS_DECRYPT_RESULT="$(dd if="$ENCPASS_SECRET_ABS_NAME" ibs=1 skip=32 2> /dev/null | openssl enc -aes-256-cbc \
-d -a -iv "$(head -c 32 "$ENCPASS_SECRET_ABS_NAME")" -K "$(cat "$ENCPASS_PRIVATE_KEY_ABS_NAME")" 2> /dev/null)"
if [ ! -z "$ENCPASS_DECRYPT_RESULT" ]; then
echo "$ENCPASS_DECRYPT_RESULT"
else
# If a failed unlock command occurred and the user tries to show the secret
# Present either locked or decrypt command
if [ -f "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.lock" ]; then
echo "**Locked**"
else
# The locked file wasn't present as expected. Let's display a failure
echo "Error: Failed to decrypt"
fi
fi
Elif [ -f "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.lock" ]; then
echo "**Locked**"
else
echo "Error: Unable to decrypt. The key file \"$ENCPASS_PRIVATE_KEY_ABS_NAME\" is not present."
fi
}
##########################################################
# COMMAND LINE MANAGEMENT SUPPORT
# -------------------------------
# If you don't need to manage the secrets for the scripts
# with encpass.sh you can delete all code below this point
# in order to significantly reduce the size of encpass.sh.
# This is useful if you want to bundle encpass.sh with
# your existing scripts and just need the retrieval
# functions.
##########################################################
encpass_show_secret() {
encpass_checks
ENCPASS_BUCKET=$1
encpass_get_private_key_abs_name "nogenerate"
if [ ! -z "$2" ]; then
ENCPASS_SECRET_NAME=$2
encpass_get_secret_abs_name "$1" "$2" "nocreate"
if [ -z "$ENCPASS_SECRET_ABS_NAME" ]; then
echo "No secret named $2 found for bucket $1."
exit 1
fi
encpass_decrypt_secret
else
ENCPASS_FILE_LIST=$(ls -1 "$ENCPASS_HOME_DIR"/secrets/"$1")
for ENCPASS_F in $ENCPASS_FILE_LIST; do
ENCPASS_SECRET_NAME=$(basename "$ENCPASS_F" .enc)
encpass_get_secret_abs_name "$1" "$ENCPASS_SECRET_NAME" "nocreate"
if [ -z "$ENCPASS_SECRET_ABS_NAME" ]; then
echo "No secret named $ENCPASS_SECRET_NAME found for bucket $1."
exit 1
fi
echo "$ENCPASS_SECRET_NAME = $(encpass_decrypt_secret)"
done
fi
}
encpass_getche() {
old=$(stty -g)
stty raw min 1 time 0
printf '%s' "$(dd bs=1 count=1 2>/dev/null)"
stty "$old"
}
encpass_remove() {
if [ ! -n "$ENCPASS_FORCE_REMOVE" ]; then
if [ ! -z "$ENCPASS_SECRET" ]; then
printf "Are you sure you want to remove the secret \"%s\" from bucket \"%s\"? [y/N]" "$ENCPASS_SECRET" "$ENCPASS_BUCKET"
else
printf "Are you sure you want to remove the bucket \"%s?\" [y/N]" "$ENCPASS_BUCKET"
fi
ENCPASS_CONFIRM="$(encpass_getche)"
printf "\n"
if [ "$ENCPASS_CONFIRM" != "Y" ] && [ "$ENCPASS_CONFIRM" != "y" ]; then
exit 0
fi
fi
if [ ! -z "$ENCPASS_SECRET" ]; then
rm -f "$1"
printf "Secret \"%s\" removed from bucket \"%s\".\n" "$ENCPASS_SECRET" "$ENCPASS_BUCKET"
else
rm -Rf "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET"
rm -Rf "$ENCPASS_HOME_DIR/secrets/$ENCPASS_BUCKET"
printf "Bucket \"%s\" removed.\n" "$ENCPASS_BUCKET"
fi
}
encpass_save_err() {
if read -r x; then
{ printf "%s\n" "$x"; cat; } > "$1"
Elif [ "$x" != "" ]; then
printf "%s" "$x" > "$1"
fi
}
encpass_help() {
less << EOF
NAME:
encpass.sh - Use encrypted passwords in Shell scripts
DESCRIPTION:
A lightweight solution for using encrypted passwords in Shell scripts
using OpenSSL. It allows a user to encrypt a password (or any other secret)
at runtime and then use it, decrypted, within a script. This prevents
shoulder surfing passwords and avoids storing the password in plain text,
within a script, which could inadvertently be sent to or discovered by an
individual at a later date.
This script generates an AES 256 bit symmetric key for each script
(or user-defined bucket) that stores secrets. This key will then be used
to encrypt all secrets for that script or bucket.
Subsequent calls to retrieve a secret will not Prompt for a secret to be
entered as the file with the encrypted value already exists.
Note: By default, encpass.sh sets up a directory (.encpass) under the
user's home directory where keys and secrets will be stored. This directory
can be overridden by setting the environment variable ENCPASS_HOME_DIR to a
directory of your choice.
~/.encpass (or the directory specified by ENCPASS_HOME_DIR) will contain
the following subdirectories:
- keys (Holds the private key for each script/bucket)
- secrets (Holds the secrets stored for each script/bucket)
USAGE:
To use the encpass.sh script in an existing Shell script, source the script
and then call the get_secret function.
Example:
#!/bin/sh
. encpass.sh
password=\$(get_secret)
When no arguments are passed to the get_secret function,
then the bucket name is set to the name of the script and
the secret name is set to "password".
There are 2 other ways to call get_secret:
Specify the secret name:
Ex: \$(get_secret user)
- bucket name = <script name>
- secret name = "user"
Specify both the secret name and bucket name:
Ex: \$(get_secret personal user)
- bucket name = "personal"
- secret name = "user"
encpass.sh also provides a command line interface to manage the secrets.
To invoke a command, pass it as an argument to encpass.sh from the Shell.
$ encpass.sh [COMMAND]
See the COMMANDS section below for a list of available commands. Wildcard
handling is implemented for secret and bucket names. This enables
performing operations like adding/removing a secret to/from multiple buckets
at once.
COMMANDS:
add [-f] <bucket> <secret>
Add a secret to the specified bucket. The bucket will be created
if it does not already exist. If a secret with the same name already
exists for the specified bucket, then the user will be prompted to
confirm overwriting the value. If the -f option is passed, then the
add operation will perform a forceful overwrite of the value. (i.e. no
Prompt)
list|ls [<bucket>]
Display the names of the secrets held in the bucket. If no bucket
is specified, then the names of all existing buckets will be
displayed.
lock
Locks all keys used by encpass.sh using a password. The user
will be prompted to enter a password and confirm it. A user
should take care to securely store the password. If the password
is lost then keys can not be unlocked. When keys are locked,
secrets can not be retrieved. (e.g. the output of the values
in the "show" command will be encrypted/garbage)
remove|rm [-f] <bucket> [<secret>]
Remove a secret from the specified bucket. If only a bucket is
specified then the entire bucket (i.e. all secrets and keys) will
be removed. By default the user is asked to confirm the removal of
the secret or the bucket. If the -f option is passed then a
forceful removal will be performed. (i.e. no Prompt)
show [<bucket>] [<secret>]
Show the unencrypted value of the secret from the specified bucket.
If no secret is specified then all secrets for the bucket are displayed.
update <bucket> <secret>
Updates a secret in the specified bucket. This command is similar
to using an "add -f" command, but it has a safety check to only
proceed if the specified secret exists. If the secret, does not
already exist, then an error will be reported. There is no forceable
update implemented. Use "add -f" for any required forceable update
scenarios.
unlock
Unlocks all the keys for encpass.sh. The user will be prompted to
enter the password and confirm it.
dir
Prints out the current value of the ENCPASS_HOME_DIR environment variable.
help|--help|usage|--usage|?
Display this help message.
EOF
}
# Subcommands for cli support
case "$1" in
add )
shift
while getopts ":f" ENCPASS_OPTS; do
case "$ENCPASS_OPTS" in
f ) ENCPASS_FORCE_ADD=1;;
esac
done
encpass_checks
if [ -n "$ENCPASS_FORCE_ADD" ]; then
shift $((OPTIND-1))
fi
if [ ! -z "$1" ] && [ ! -z "$2" ]; then
# Allow globbing
# shellcheck disable=SC2027,SC2086
ENCPASS_ADD_LIST="$(ls -1d "$ENCPASS_HOME_DIR/secrets/"$1"" 2>/dev/null)"
if [ -z "$ENCPASS_ADD_LIST" ]; then
ENCPASS_ADD_LIST="$1"
fi
for ENCPASS_ADD_F in $ENCPASS_ADD_LIST; do
ENCPASS_ADD_DIR="$(basename "$ENCPASS_ADD_F")"
ENCPASS_BUCKET="$ENCPASS_ADD_DIR"
if [ ! -n "$ENCPASS_FORCE_ADD" ] && [ -f "$ENCPASS_ADD_F/$2.enc" ]; then
echo "Warning: A secret with the name \"$2\" already exists for bucket $ENCPASS_BUCKET."
echo "Would you like to overwrite the value? [y/N]"
ENCPASS_CONFIRM="$(encpass_getche)"
if [ "$ENCPASS_CONFIRM" != "Y" ] && [ "$ENCPASS_CONFIRM" != "y" ]; then
continue
fi
fi
ENCPASS_SECRET_NAME="$2"
echo "Adding secret \"$ENCPASS_SECRET_NAME\" to bucket \"$ENCPASS_BUCKET\"..."
set_secret "$ENCPASS_BUCKET" "$ENCPASS_SECRET_NAME" "reuse"
done
else
echo "Error: A bucket name and secret name must be provided when adding a secret."
exit 1
fi
;;
update )
shift
encpass_checks
if [ ! -z "$1" ] && [ ! -z "$2" ]; then
ENCPASS_SECRET_NAME="$2"
# Allow globbing
# shellcheck disable=SC2027,SC2086
ENCPASS_UPDATE_LIST="$(ls -1d "$ENCPASS_HOME_DIR/secrets/"$1"" 2>/dev/null)"
for ENCPASS_UPDATE_F in $ENCPASS_UPDATE_LIST; do
# Allow globbing
# shellcheck disable=SC2027,SC2086
if [ -f "$ENCPASS_UPDATE_F/"$2".enc" ]; then
ENCPASS_UPDATE_DIR="$(basename "$ENCPASS_UPDATE_F")"
ENCPASS_BUCKET="$ENCPASS_UPDATE_DIR"
echo "Updating secret \"$ENCPASS_SECRET_NAME\" to bucket \"$ENCPASS_BUCKET\"..."
set_secret "$ENCPASS_BUCKET" "$ENCPASS_SECRET_NAME" "reuse"
else
echo "Error: A secret with the name \"$2\" does not exist for bucket $1."
exit 1
fi
done
else
echo "Error: A bucket name and secret name must be provided when updating a secret."
exit 1
fi
;;
rm|remove )
shift
encpass_checks
while getopts ":f" ENCPASS_OPTS; do
case "$ENCPASS_OPTS" in
f ) ENCPASS_FORCE_REMOVE=1;;
esac
done
if [ -n "$ENCPASS_FORCE_REMOVE" ]; then
shift $((OPTIND-1))
fi
if [ -z "$1" ]; then
echo "Error: A bucket must be specified for removal."
fi
# Allow globbing
# shellcheck disable=SC2027,SC2086
ENCPASS_REMOVE_BKT_LIST="$(ls -1d "$ENCPASS_HOME_DIR/secrets/"$1"" 2>/dev/null)"
if [ ! -z "$ENCPASS_REMOVE_BKT_LIST" ]; then
for ENCPASS_REMOVE_B in $ENCPASS_REMOVE_BKT_LIST; do
ENCPASS_BUCKET="$(basename "$ENCPASS_REMOVE_B")"
if [ ! -z "$2" ]; then
# Removing secrets for a specified bucket
# Allow globbing
# shellcheck disable=SC2027,SC2086
ENCPASS_REMOVE_LIST="$(ls -1p "$ENCPASS_REMOVE_B/"$2".enc" 2>/dev/null)"
if [ -z "$ENCPASS_REMOVE_LIST" ]; then
echo "Error: No secrets found for $2 in bucket $ENCPASS_BUCKET."
exit 1
fi
for ENCPASS_REMOVE_F in $ENCPASS_REMOVE_LIST; do
ENCPASS_SECRET="$2"
encpass_remove "$ENCPASS_REMOVE_F"
done
else
# Removing a specified bucket
encpass_remove
fi
done
else
echo "Error: The bucket named $1 does not exist."
exit 1
fi
;;
show )
shift
encpass_checks
if [ -z "$1" ]; then
ENCPASS_SHOW_DIR="*"
else
ENCPASS_SHOW_DIR=$1
fi
if [ ! -z "$2" ]; then
# Allow globbing
# shellcheck disable=SC2027,SC2086
if [ -f "$(encpass_get_abs_filename "$ENCPASS_HOME_DIR/secrets/$ENCPASS_SHOW_DIR/"$2".enc")" ]; then
encpass_show_secret "$ENCPASS_SHOW_DIR" "$2"
fi
else
# Allow globbing
# shellcheck disable=SC2027,SC2086
ENCPASS_SHOW_LIST="$(ls -1d "$ENCPASS_HOME_DIR/secrets/"$ENCPASS_SHOW_DIR"" 2>/dev/null)"
if [ -z "$ENCPASS_SHOW_LIST" ]; then
if [ "$ENCPASS_SHOW_DIR" = "*" ]; then
echo "Error: No buckets exist."
else
echo "Error: Bucket $1 does not exist."
fi
exit 1
fi
for ENCPASS_SHOW_F in $ENCPASS_SHOW_LIST; do
ENCPASS_SHOW_DIR="$(basename "$ENCPASS_SHOW_F")"
echo "$ENCPASS_SHOW_DIR:"
encpass_show_secret "$ENCPASS_SHOW_DIR"
echo " "
done
fi
;;
ls|list )
shift
encpass_checks
if [ ! -z "$1" ]; then
# Allow globbing
# shellcheck disable=SC2027,SC2086
ENCPASS_FILE_LIST="$(ls -1p "$ENCPASS_HOME_DIR/secrets/"$1"" 2>/dev/null)"
if [ -z "$ENCPASS_FILE_LIST" ]; then
# Allow globbing
# shellcheck disable=SC2027,SC2086
ENCPASS_DIR_EXISTS="$(ls -d "$ENCPASS_HOME_DIR/secrets/"$1"" 2>/dev/null)"
if [ ! -z "$ENCPASS_DIR_EXISTS" ]; then
echo "Bucket $1 is empty."
else
echo "Error: Bucket $1 does not exist."
fi
exit 1
fi
ENCPASS_NL=""
for ENCPASS_F in $ENCPASS_FILE_LIST; do
if [ -d "${ENCPASS_F%:}" ]; then
printf "$ENCPASS_NL%s\n" "$(basename "$ENCPASS_F")"
ENCPASS_NL="\n"
else
printf "%s\n" "$(basename "$ENCPASS_F" .enc)"
fi
done
else
# Allow globbing
# shellcheck disable=SC2027,SC2086
ENCPASS_BUCKET_LIST="$(ls -1p "$ENCPASS_HOME_DIR/secrets/"$1"" 2>/dev/null)"
for ENCPASS_C in $ENCPASS_BUCKET_LIST; do
if [ -d "${ENCPASS_C%:}" ]; then
printf "\n%s" "\n$(basename "$ENCPASS_C")"
else
basename "$ENCPASS_C" .enc
fi
done
fi
;;
lock )
shift
encpass_checks
echo "************************!!!WARNING!!!*************************" >&2
echo "* You are about to lock your keys with a password. *" >&2
echo "* You will not be able to use your secrets again until you *" >&2
echo "* unlock the keys with the same password. It is important *" >&2
echo "* that you securely store the password, so you can recall it *" >&2
echo "* in the future. If you forget your password you will no *" >&2
echo "* longer be able to access your secrets. *" >&2
echo "************************!!!WARNING!!!*************************" >&2
printf "\n%s\n" "About to lock keys held in directory $ENCPASS_HOME_DIR/keys/"
printf "\nEnter Password to lock keys:" >&2
stty -echo
read -r ENCPASS_KEY_PASS
printf "\nConfirm Password:" >&2
read -r ENCPASS_CKEY_PASS
printf "\n"
stty echo
if [ -z "$ENCPASS_KEY_PASS" ]; then
echo "Error: You must supply a password value."
exit 1
fi
if [ "$ENCPASS_KEY_PASS" = "$ENCPASS_CKEY_PASS" ]; then
ENCPASS_NUM_KEYS_LOCKED=0
ENCPASS_KEYS_LIST="$(ls -1d "$ENCPASS_HOME_DIR/keys/"*"/" 2>/dev/null)"
for ENCPASS_KEY_F in $ENCPASS_KEYS_LIST; do
if [ -d "${ENCPASS_KEY_F%:}" ]; then
ENCPASS_KEY_NAME="$(basename "$ENCPASS_KEY_F")"
ENCPASS_KEY_VALUE=""
if [ -f "$ENCPASS_KEY_F/private.key" ]; then
ENCPASS_KEY_VALUE="$(cat "$ENCPASS_KEY_F/private.key")"
if [ ! -f "$ENCPASS_KEY_F/private.lock" ]; then
echo "Locking key $ENCPASS_KEY_NAME..."
else
echo "Error: The key $ENCPASS_KEY_NAME appears to have been previously locked."
echo " The current key file may hold a bad value. Exiting to avoid encrypting"
echo " a bad value and overwriting the lock file."
exit 1
fi
else
echo "Error: Private key file ${ENCPASS_KEY_F}private.key missing for bucket $ENCPASS_KEY_NAME."
exit 1
fi
if [ ! -z "$ENCPASS_KEY_VALUE" ]; then
openssl enc -aes-256-cbc -pbkdf2 -iter 10000 -salt -in "$ENCPASS_KEY_F/private.key" -out "$ENCPASS_KEY_F/private.lock" -k "$ENCPASS_KEY_PASS"
if [ -f "$ENCPASS_KEY_F/private.key" ] && [ -f "$ENCPASS_KEY_F/private.lock" ]; then
# Both the key and lock file exist. We can remove the key file now
rm -f "$ENCPASS_KEY_F/private.key"
echo "Locked key $ENCPASS_KEY_NAME."
ENCPASS_NUM_KEYS_LOCKED=$(( ENCPASS_NUM_KEYS_LOCKED + 1 ))
else
echo "Error: The key fle and/or lock file were not found as expected for key $ENCPASS_KEY_NAME."
fi
else
echo "Error: No key value found for the $ENCPASS_KEY_NAME key."
exit 1
fi
fi
done
echo "Locked $ENCPASS_NUM_KEYS_LOCKED keys."
else
echo "Error: Passwords do not match."
fi
;;
unlock )
shift
encpass_checks
printf "%s\n" "About to unlock keys held in the $ENCPASS_HOME_DIR/keys/ directory."
printf "\nEnter Password to unlock keys: " >&2
stty -echo
read -r ENCPASS_KEY_PASS
printf "\n"
stty echo
if [ ! -z "$ENCPASS_KEY_PASS" ]; then
ENCPASS_NUM_KEYS_UNLOCKED=0
ENCPASS_KEYS_LIST="$(ls -1d "$ENCPASS_HOME_DIR/keys/"*"/" 2>/dev/null)"
for ENCPASS_KEY_F in $ENCPASS_KEYS_LIST; do
if [ -d "${ENCPASS_KEY_F%:}" ]; then
ENCPASS_KEY_NAME="$(basename "$ENCPASS_KEY_F")"
echo "Unlocking key $ENCPASS_KEY_NAME..."
if [ -f "$ENCPASS_KEY_F/private.key" ] && [ ! -f "$ENCPASS_KEY_F/private.lock" ]; then
echo "Error: Key $ENCPASS_KEY_NAME appears to be unlocked already."
exit 1
fi
if [ -f "$ENCPASS_KEY_F/private.lock" ]; then
# Remove the failed file in case previous decryption attempts were unsuccessful
rm -f "$ENCPASS_KEY_F/failed" 2>/dev/null
# Decrypt key. Log any failure to the "failed" file.
openssl enc -aes-256-cbc -d -pbkdf2 -iter 10000 -salt \
-in "$ENCPASS_KEY_F/private.lock" -out "$ENCPASS_KEY_F/private.key" \
-k "$ENCPASS_KEY_PASS" 2>&1 | encpass_save_err "$ENCPASS_KEY_F/failed"
if [ ! -f "$ENCPASS_KEY_F/failed" ]; then
# No failure has occurred.
if [ -f "$ENCPASS_KEY_F/private.key" ] && [ -f "$ENCPASS_KEY_F/private.lock" ]; then
# Both the key and lock file exist. We can remove the lock file now.
rm -f "$ENCPASS_KEY_F/private.lock"
echo "Unlocked key $ENCPASS_KEY_NAME."
ENCPASS_NUM_KEYS_UNLOCKED=$(( ENCPASS_NUM_KEYS_UNLOCKED + 1 ))
else
echo "Error: The key file and/or lock file were not found as expected for key $ENCPASS_KEY_NAME."
fi
else
printf "Error: Failed to unlock key %s.\n" "$ENCPASS_KEY_NAME"
printf " Please view %sfailed for details.\n" "$ENCPASS_KEY_F"
fi
else
echo "Error: No lock file found for the $ENCPASS_KEY_NAME key."
fi
fi
done
echo "Unlocked $ENCPASS_NUM_KEYS_UNLOCKED keys."
else
echo "No password entered."
fi
;;
dir )
shift
encpass_checks
echo "ENCPASS_HOME_DIR=$ENCPASS_HOME_DIR"
;;
help|--help|usage|--usage|\? )
encpass_checks
encpass_help
;;
* )
if [ ! -z "$1" ]; then
echo "Command not recognized. See \"encpass.sh help\" for a list commands."
exit 1
fi
;;
esac
Il existe un moyen de stocker les mots de passe dans un script bash mais vous devez crypter et obscurcir le script afin que personne ne puisse le lire ou exécuter n'importe quel type de débogueur dessus pour voir exactement ce qu'il fait. Pour chiffrer et obscurcir un script bash/Shell et qu'il soit réellement exécutable, essayez de le copier et de le coller ici:
http://www.kinglazy.com/Shell-script-encryption-kinglazy-shieldx.htm
Sur la page ci-dessus, tout ce que vous avez à faire est de soumettre votre script (vous pouvez d'abord soumettre un exemple de script pour votre tranquillité d'esprit). Un fichier Zip sera généré pour vous. Faites un clic droit sur le lien de téléchargement et copiez l'URL qui vous est fournie. Ensuite, accédez à votre boîte UNIX et effectuez les étapes suivantes.
Installation:
wget lien vers le fichier Zip
décompressez le fichier Zip nouvellement téléchargé
cd/tmp/KingLazySHIELD
./install.sh/var/tmp/KINGLAZY/SHIELDX- (votre-nom-de-script)/home/(votre-nom-d'utilisateur) -force
Ce que la commande d'installation ci-dessus fera pour vous:
Il installera la version chiffrée de votre script dans le répertoire/var/tmp/KINGLAZY/SHIELDX- (votre-nom-script).
Il placera un lien vers ce script crypté dans le répertoire que vous spécifiez en remplacement de/home/(votre-nom d'utilisateur) - de cette façon, il vous permet d'accéder facilement au script sans avoir à taper le chemin absolu.
Garantit que PERSONNE ne peut modifier le script - Toute tentative de modification du script crypté le rendra inutilisable ... jusqu'à ce que ces tentatives soient arrêtées ou supprimées. Il peut même être configuré pour vous avertir chaque fois que quelqu'un essaie de faire autre chose avec le script que de l'exécuter ... c'est-à-dire. tentatives de piratage ou de modification.
Garantit que personne ne peut en faire de copie. Personne ne peut copier votre script dans un endroit isolé et essayer de le contourner pour voir comment cela fonctionne. Toutes les copies du script doivent être des liens vers l'emplacement d'origine que vous avez spécifié lors de l'installation (étape 4).
REMARQUE:
Je ne pense pas que cela fonctionne pour les scripts interactifs qui invitent l'utilisateur à répondre. Les valeurs doivent être codées en dur dans le script. Le chiffrement garantit que personne ne peut réellement voir ces valeurs, vous n'avez donc pas à vous en soucier.
Une autre solution, sans égard à la sécurité (je pense aussi qu'il vaut mieux conserver les informations d'identification dans un autre fichier ou dans une base de données) est de crypter le mot de passe avec gpg et de l'insérer dans le script.
J'utilise une paire de clés gpg sans mot de passe que je garde dans une clé USB. (Remarque: lorsque vous exportez cette paire de clés, n'utilisez pas --armor, exportez-les au format binaire).
Cryptez d'abord votre mot de passe:
echo -n "pAssw0rd" | gpg --armor --no-default-keyring --keyring /media/usb/key.pub --recipient [email protected] --encrypt
Ce sera imprimé le mot de passe crypté gpg dans la sortie standard. Copiez l'intégralité du message et ajoutez-le au script:
password=$(gpg --batch --quiet --no-default-keyring --secret-keyring /media/usb/key.priv --decrypt <<EOF
-----BEGIN PGP MESSAGE-----
hQEMA0CjbyauRLJ8AQgAkZT5gK8TrdH6cZEy+Ufl0PObGZJ1YEbshacZb88RlRB9
h2z+s/Bso5HQxNd5tzkwulvhmoGu6K6hpMXM3mbYl07jHF4qr+oWijDkdjHBVcn5
0mkpYO1riUf0HXIYnvCZq/4k/ajGZRm8EdDy2JIWuwiidQ18irp07UUNO+AB9mq8
5VXUjUN3tLTexg4sLZDKFYGRi4fyVrYKGsi0i5AEHKwn5SmTb3f1pa5yXbv68eYE
lCVfy51rBbG87UTycZ3gFQjf1UkNVbp0WV+RPEM9JR7dgR+9I8bKCuKLFLnGaqvc
beA3A6eMpzXQqsAg6GGo3PW6fMHqe1ZCvidi6e4a/dJDAbHq0XWp93qcwygnWeQW
Ozr1hr5mCa+QkUSymxiUrRncRhyqSP0ok5j4rjwSJu9vmHTEUapiyQMQaEIF2e2S
/NIWGg==
=uriR
-----END PGP MESSAGE-----
EOF)
De cette façon, uniquement si l'USB est monté dans le système, le mot de passe peut être déchiffré. Bien sûr, vous pouvez également importer les clés dans le système (moins sécurisées ou pas de sécurité du tout) ou vous pouvez protéger la clé privée avec un mot de passe (de sorte qu'elle ne peut pas être automatisée).