You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
7.6 KiB
271 lines
7.6 KiB
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Git Pusher - Credentials Manager
|
|
Gère les credentials de manière sécurisée via Splunk storage/passwords
|
|
ou via un fichier chiffré local.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import json
|
|
import base64
|
|
import hashlib
|
|
from pathlib import Path
|
|
|
|
# Chemin vers le fichier de credentials chiffré
|
|
CREDENTIALS_FILE = "/opt/splunk/etc/apps/pusher_app_prem/local/.credentials"
|
|
ENCRYPTION_KEY_FILE = "/opt/splunk/etc/apps/pusher_app_prem/local/.key"
|
|
|
|
|
|
def get_machine_id():
|
|
"""Obtenir un identifiant unique de la machine pour le chiffrement"""
|
|
machine_id = ""
|
|
|
|
# Essayer différentes sources
|
|
try:
|
|
with open('/etc/machine-id', 'r') as f:
|
|
machine_id = f.read().strip()
|
|
except:
|
|
pass
|
|
|
|
if not machine_id:
|
|
try:
|
|
import socket
|
|
machine_id = socket.gethostname()
|
|
except:
|
|
machine_id = "default_key"
|
|
|
|
return machine_id
|
|
|
|
|
|
def derive_key(password, salt=None):
|
|
"""Dériver une clé de chiffrement à partir d'un mot de passe"""
|
|
if salt is None:
|
|
salt = get_machine_id().encode()
|
|
|
|
# Utiliser PBKDF2-like avec SHA256
|
|
key = hashlib.pbkdf2_hmac(
|
|
'sha256',
|
|
password.encode(),
|
|
salt,
|
|
100000
|
|
)
|
|
return base64.b64encode(key).decode()
|
|
|
|
|
|
def simple_encrypt(data, key):
|
|
"""Chiffrement simple XOR (pour une sécurité basique)"""
|
|
# Pour une vraie sécurité, utiliser cryptography.fernet
|
|
key_bytes = key.encode() * (len(data) // len(key) + 1)
|
|
encrypted = bytes([a ^ b for a, b in zip(data.encode(), key_bytes[:len(data)])])
|
|
return base64.b64encode(encrypted).decode()
|
|
|
|
|
|
def simple_decrypt(encrypted_data, key):
|
|
"""Déchiffrement simple XOR"""
|
|
try:
|
|
data = base64.b64decode(encrypted_data)
|
|
key_bytes = key.encode() * (len(data) // len(key) + 1)
|
|
decrypted = bytes([a ^ b for a, b in zip(data, key_bytes[:len(data)])])
|
|
return decrypted.decode()
|
|
except Exception as e:
|
|
return None
|
|
|
|
|
|
def get_encryption_key():
|
|
"""Obtenir ou créer la clé de chiffrement"""
|
|
if os.path.exists(ENCRYPTION_KEY_FILE):
|
|
with open(ENCRYPTION_KEY_FILE, 'r') as f:
|
|
return f.read().strip()
|
|
else:
|
|
# Générer une nouvelle clé basée sur la machine
|
|
key = derive_key(get_machine_id())
|
|
|
|
# Sauvegarder la clé
|
|
os.makedirs(os.path.dirname(ENCRYPTION_KEY_FILE), exist_ok=True)
|
|
with open(ENCRYPTION_KEY_FILE, 'w') as f:
|
|
f.write(key)
|
|
|
|
# Protéger le fichier
|
|
os.chmod(ENCRYPTION_KEY_FILE, 0o600)
|
|
|
|
return key
|
|
|
|
|
|
def save_credentials(username, password):
|
|
"""Sauvegarder les credentials de manière chiffrée"""
|
|
key = get_encryption_key()
|
|
|
|
credentials = {
|
|
'username': username,
|
|
'password': simple_encrypt(password, key)
|
|
}
|
|
|
|
os.makedirs(os.path.dirname(CREDENTIALS_FILE), exist_ok=True)
|
|
|
|
with open(CREDENTIALS_FILE, 'w') as f:
|
|
json.dump(credentials, f)
|
|
|
|
# Protéger le fichier
|
|
os.chmod(CREDENTIALS_FILE, 0o600)
|
|
|
|
print(f"✓ Credentials saved securely to {CREDENTIALS_FILE}")
|
|
|
|
|
|
def load_credentials():
|
|
"""Charger les credentials chiffrés"""
|
|
if not os.path.exists(CREDENTIALS_FILE):
|
|
return None, None
|
|
|
|
try:
|
|
key = get_encryption_key()
|
|
|
|
with open(CREDENTIALS_FILE, 'r') as f:
|
|
credentials = json.load(f)
|
|
|
|
username = credentials.get('username')
|
|
encrypted_password = credentials.get('password')
|
|
|
|
password = simple_decrypt(encrypted_password, key)
|
|
|
|
return username, password
|
|
|
|
except Exception as e:
|
|
print(f"Error loading credentials: {e}", file=sys.stderr)
|
|
return None, None
|
|
|
|
|
|
def delete_credentials():
|
|
"""Supprimer les credentials stockés"""
|
|
if os.path.exists(CREDENTIALS_FILE):
|
|
os.remove(CREDENTIALS_FILE)
|
|
print("✓ Credentials deleted")
|
|
else:
|
|
print("No credentials file found")
|
|
|
|
|
|
def get_credentials_for_script():
|
|
"""
|
|
Fonction utilisée par le script de démarrage pour obtenir les credentials.
|
|
Retourne username et password, ou None si non configurés.
|
|
"""
|
|
username, password = load_credentials()
|
|
|
|
if username and password:
|
|
return username, password
|
|
|
|
# Fallback sur les variables d'environnement
|
|
env_user = os.environ.get('SPLUNK_USERNAME')
|
|
env_pass = os.environ.get('SPLUNK_PASSWORD')
|
|
|
|
if env_user and env_pass:
|
|
return env_user, env_pass
|
|
|
|
return None, None
|
|
|
|
|
|
# ============================================
|
|
# CLI
|
|
# ============================================
|
|
|
|
def interactive_setup():
|
|
"""Configuration interactive des credentials"""
|
|
print("=" * 50)
|
|
print("Git Pusher - Credentials Setup")
|
|
print("=" * 50)
|
|
print()
|
|
print("This will securely store your Splunk credentials.")
|
|
print(f"Credentials will be encrypted and saved to:")
|
|
print(f" {CREDENTIALS_FILE}")
|
|
print()
|
|
|
|
username = input("Splunk Username [admin]: ").strip() or "admin"
|
|
|
|
import getpass
|
|
password = getpass.getpass("Splunk Password: ")
|
|
|
|
if not password:
|
|
print("Error: Password cannot be empty")
|
|
return
|
|
|
|
# Confirmer
|
|
password2 = getpass.getpass("Confirm Password: ")
|
|
|
|
if password != password2:
|
|
print("Error: Passwords do not match")
|
|
return
|
|
|
|
save_credentials(username, password)
|
|
print()
|
|
print("✓ Credentials configured successfully!")
|
|
print()
|
|
print("You can now start Git Pusher without specifying credentials:")
|
|
print(" ./start_git_pusher.sh start")
|
|
|
|
|
|
def show_status():
|
|
"""Afficher le statut des credentials"""
|
|
print("=" * 50)
|
|
print("Credentials Status")
|
|
print("=" * 50)
|
|
|
|
if os.path.exists(CREDENTIALS_FILE):
|
|
print(f"✓ Credentials file exists: {CREDENTIALS_FILE}")
|
|
|
|
username, password = load_credentials()
|
|
if username:
|
|
print(f" Username: {username}")
|
|
print(f" Password: {'*' * len(password) if password else 'ERROR'}")
|
|
else:
|
|
print(" Error: Could not decrypt credentials")
|
|
else:
|
|
print("✗ No credentials file found")
|
|
print()
|
|
print("Run: python credentials_manager.py setup")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
if len(sys.argv) < 2:
|
|
show_status()
|
|
sys.exit(0)
|
|
|
|
command = sys.argv[1]
|
|
|
|
if command == 'setup':
|
|
interactive_setup()
|
|
|
|
elif command == 'status':
|
|
show_status()
|
|
|
|
elif command == 'delete':
|
|
delete_credentials()
|
|
|
|
elif command == 'get':
|
|
# Pour utilisation dans les scripts bash
|
|
username, password = get_credentials_for_script()
|
|
if username and password:
|
|
print(f"{username}")
|
|
print(f"{password}")
|
|
else:
|
|
sys.exit(1)
|
|
|
|
elif command == 'export':
|
|
# Exporter pour utilisation dans bash
|
|
username, password = get_credentials_for_script()
|
|
if username and password:
|
|
print(f"export SPLUNK_USERNAME='{username}'")
|
|
print(f"export SPLUNK_PASSWORD='{password}'")
|
|
else:
|
|
print("# No credentials found", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
else:
|
|
print("Usage: python credentials_manager.py [setup|status|delete|get|export]")
|
|
print()
|
|
print("Commands:")
|
|
print(" setup - Configure credentials interactively")
|
|
print(" status - Show credentials status")
|
|
print(" delete - Delete stored credentials")
|
|
print(" get - Output credentials (for scripts)")
|
|
print(" export - Output as bash export commands") |