Intro
Le durcissement de la sécurité pour Apache Spark est le plus efficace lorsque vous appliquez un petit ensemble de contrôles éprouvés avec des résultats clairs et testables. Ce guide vous donne un flux de travail pratique, un plan pilote local sûr et des exemples copiables pour le contrôle d'accès, les secrets, les permissions, l'exposition réseau et les vérifications de validation.
Ce que vous obtiendrez :
- Un flux de travail de durcissement répétable pour réduire le retravail
- Un plan pilote local d'abord que vous pouvez exécuter en moins d'une heure
- Des réglages Spark concrets pour les ACLs (Access Control Lists) : listes de contrôle d'accès, les secrets et le chiffrement
- Des vérifications rapides pour prouver que le durcissement fonctionne réellement
Ce qu'il faut sécuriser dans Spark
Spark se situe au centre de votre plateforme de données et interagit avec plusieurs services. Concentrez-vous sur cinq domaines :
- Accès et actions — Qui peut consulter les UI (User Interface) : interfaces utilisateur (driver, executor, history server) ? Qui peut soumettre, annuler ou modifier des jobs ?
- Permissions sous Spark — Permissions HDFS ou stockage objet ; comptes de service et rôles Kubernetes/YARN
- Secrets — Identifiants fournisseur cloud ; matériel d'authentification base de données, Kafka, HDFS
- Données en mouvement — Trafic RPC (Remote Procedure Call) : appel de procédure à distance et shuffle internes Spark ; connecteurs externes (JDBC, Kafka, stockage cloud)
- Exposition réseau — Adresses et ports de liaison du driver et des executors ; exposition des UI et reverse proxying
Aperçu du workflow
Utilisez un flux court et répétable qui évite les changements "big-bang" :
- Définir le périmètre et le succès — Choisissez un job représentatif (par exemple, un ETL quotidien qui lit du Parquet sur S3 et écrit les résultats agrégés dans un entrepôt) et 3 à 5 contrôles à activer (ACLs, rédaction des logs, auth interne, crypto réseau, UI derrière proxy). Énoncez des résultats mesurables : un utilisateur non autorisé ne peut pas voir l'UI ; les secrets n'apparaissent pas dans les logs.
- Baseline — Capturez les configurations actuelles et les ports ouverts.
- Appliquer les contrôles en dev — Changez seulement ce que vous mesurez ; gardez les diffs petits et documentés.
- Valider localement — Exécutez des vérifications rapides ; capturez les preuves (commandes, captures d'écran, logs).
- Promouvoir avec une checklist — Déployez les changements vers l'avant, en gardant les valeurs spécifiques à l'environnement dans des fichiers de config ou des magasins de secrets.
Plan pilote local
Périmètre : un job Spark qui lit depuis le stockage et écrit les résultats (par exemple, un simple word-count ou job ETL lisant depuis un bucket de test et écrivant vers un chemin de sortie), plus l'UI d'historique.
Contrôles à activer en premier :
- Contrôle d'accès : ACLs pour vue/modification
- Secrets : rédaction des logs et aucun secret en ligne de commande
- Protection interne : authentification et crypto réseau
- Exposition : liaison sur interfaces internes et UI derrière un proxy d'auth
Résultats mesurables :
- Un utilisateur non autorisé ne peut pas voir l'UI ni tuer des jobs
- Les secrets n'apparaissent pas dans les logs driver/executor
- Spark signale l'auth interne et la crypto comme activées
- L'UI n'est pas accessible depuis des réseaux non fiables
Étapes de déploiement :
- Activer les configs ci-dessous dans un bac à sable
- Exécuter un job simple et valider
- Si tous les checks passent, appliquer les mêmes diffs en staging
Contrôle d'accès et permissions
Activez les ACLs (Access Control Lists) : listes de contrôle d'accès de Spark et définissez qui peut voir ou contrôler les jobs. Appliquez le moindre privilège sur la couche plateforme.
spark-defaults.conf (ACLs de base et contrôles UI) :
spark.acls.enable=true
spark.admin.acls=alice,bob
spark.ui.view.acls=analytics-team
spark.ui.view.acls.groups=data-readers
spark.history.ui.acls.enable=true
# Note : authz.admin.groups n'est pas une config Spark standard ; utilisez la couche d'authz de votre plateforme à la place
authz.admin.groups=platform-admins
Exemples spark-submit (overrides au niveau job) :
spark-submit \
--conf spark.acls.enable=true \
--conf spark.admin.acls=alice \
--conf spark.ui.view.acls=analytics-team \
--class com.example.Job \
local:///opt/jobs/example.jar
Permissions plateforme :
- HDFS/stockage objet : accorder lecture/écriture uniquement au rôle du job ; refuser la liste ou utiliser des politiques de bucket/dossier selon le cas
- Kubernetes : exécuter avec un compte de service dédié ; lier seulement les rôles nécessaires
- YARN : utiliser des ACLs au niveau file d'attente et Kerberos pour l'accès HDFS le cas échéant
Gestion des secrets
Principes :
- Ne jamais passer de secrets en ligne de commande ni les stocker dans le code
- Préférer les identités de charge de travail (par exemple, rôles d'instance ou de pod) aux clés statiques
- Stocker les secrets restants dans un fournisseur et les monter comme fichiers ou variables d'environnement avec le moindre privilège
- Redacter les secrets des logs
Rédaction des logs (Spark) :
spark.redaction.regex=(?i)password|secret|token|authorization|apikey
Kubernetes : monter les secrets et éviter l'exposition en CLI (Command Line Interface) : interface en ligne de commande :
spark-submit \
--master k8s://https://kubernetes.default.svc \
--conf spark.kubernetes.namespace=data \
--conf spark.kubernetes.authenticate.driver.serviceAccountName=spark-sa \
--conf spark.kubernetes.driver.secrets.app-secrets=/etc/creds \
--conf spark.executorEnv.APP_CREDENTIALS_FILE=/etc/creds/app.json \
--class com.example.Job \
local:///opt/jobs/example.jar
Fournisseur d'identifiants Hadoop (pour connecteurs qui lisent les configs Hadoop) :
# Créer un magasin JCEKS local
hadoop credential create db.password -value ***REDACTED*** -provider jceks://file/etc/creds/conn.jceks
# Le référencer dans les configs Hadoop/Spark
hadoop.security.credential.provider.path=jceks://file/etc/creds/conn.jceks
YARN avec Kerberos (exemple) :
spark-submit \
--master yarn \
--principal [email protected] \
--keytab /etc/security/keytabs/spark-user.keytab \
--class com.example.Job \
local:///opt/jobs/example.jar
Exposition réseau et chiffrement
Liez aux interfaces internes, restreignez les ports et chiffrez à la fois les communications internes Spark et toute UI exposée.
Réglages de base :
# Lier le driver à l'interface interne seulement (remplacez par votre IP ou hostname interne)
spark.driver.bindAddress=10.0.0.5
spark.driver.host=driver.internal
spark.ui.port=4040
spark.blockManager.port=7079
spark.driver.port=7078
# Auth et chiffrement internes
spark.authenticate=true
spark.network.crypto.enabled=true
spark.io.encryption.enabled=true
TLS (Transport Layer Security) : protocole de sécurité de transport pour les endpoints externes — Terminez le TLS au niveau d'un reverse proxy devant l'UI. Gardez l'UI Spark hors de l'internet public et exigez l'auth au proxy.
Exemple de NetworkPolicy Kubernetes (restreindre UI et driver) :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: spark-restrict
namespace: data
spec:
podSelector:
matchLabels:
app: spark-driver
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: platform
ports:
- protocol: TCP
port: 4040
- protocol: TCP
port: 7078
egress:
- to:
- namespaceSelector:
matchLabels:
name: storage
Si vous exposez l'UI, faites-le uniquement via un proxy qui ajoute l'authentification et la terminaison TLS. Maintenez le driver/executors Spark accessibles seulement depuis des sous-réseaux de confiance.
Vérifications de durcissement sûres
Exécutez ces vérifications rapides dans le cadre de votre pilote.
- Les ACLs fonctionnent
- Tenter d'ouvrir l'UI du job en tant qu'utilisateur non autorisé ; s'attendre à HTTP 403 au proxy ou pas de route
- Faire tenter à un utilisateur non autorisé de tuer un job ; s'attendre à un échec
- Les logs redacteur les secrets
- Soumettre un job avec un secret factice nommé TOKEN et confirmer qu'il n'apparaît pas dans les logs driver/executor
grep -iE 'password|secret|token|authorization|apikey' /path/to/driver.log || echo 'OK: redacted'
- Auth interne et crypto activées
- Afficher la SparkConf effective au démarrage du job
val conf = spark.sparkContext.getConf
println("spark.authenticate=" + conf.get("spark.authenticate" ))
println("spark.network.crypto.enabled=" + conf.get("spark.network.crypto.enabled" ))
println("spark.io.encryption.enabled=" + conf.get("spark.io.encryption.enabled" ))
S'attendre à ce que toutes les valeurs soient true.
- UI non accessible publiquement
- Depuis un réseau non fiable, tenter d'atteindre le port de l'UI ; s'attendre à un timeout ou blocage par pare-feu
- Ports et liaisons
- Confirmer que seuls les ports prévus écoutent et seulement sur les interfaces internes
ss -lntp | grep -E ':4040|:7078|:7079'
- Secrets absents de la ligne de commande
- Inspecter les arguments de processus pour spark-submit et executor ; s'attendre à aucune credential
ps aux | grep spark-submit | grep -viE 'password|secret|token|authorization|apikey'
- Permissions stockage et plateforme
- Vérifier que le rôle du job ne peut pas lire en dehors de ses buckets/chemins et que les comptes de service K8s ou YARN n'ont que les permissions requises
Conclusion
Un petit ensemble de contrôles fournit la majeure partie de la valeur : activer les ACLs, redacter les logs, exiger l'authentification interne, chiffrer le trafic interne et garder les UI hors des réseaux non fiables. Commencez par un pilote local étroit, prouvez les résultats avec des vérifications rapides, puis déployez les mêmes diffs en staging et production. À mesure que vous étendez, alignez Spark avec les systèmes environnants comme Kafka, HDFS, Apache Airflow et NiFi en utilisant les mêmes principes : moindre privilège, pas de secrets en ligne de commande et exposition réseau minimale.