L'analyse Kubernetes RBAC a rendu facile
Krane est un simple outil d'analyse statique de Kubernetes RBAC. Il identifie les risques de sécurité potentiels dans la conception du RBAC K8S et fait des suggestions sur la façon de les atténuer. Le tableau de bord Krane présente la posture de sécurité RBAC actuelle et vous permet de naviguer dans sa définition.
Vous pouvez commencer avec Krane en l'installant via le graphique de casque dans votre cluster Kubernetes cible ou en l'exécutant localement avec Docker.
Il est supposé que Helm CLI est installé sur votre machine.
$ helm repo add appvia https://appvia.github.io/krane
$ helm repo update
$ helm install krane appvia/krane --namespace krane --create-namespaceSuivez la sortie de l'installation du graphique de la barre sur la façon de porter le tableau de bord Krane à porteur de port.
Il est supposé que Docker fonctionne sur votre machine locale. Installez Docker-Compose si vous ne l'avez pas déjà fait.
Krane dépend du redisgraph. La pile docker-compose définit tout ce qui est nécessaire pour construire et exécuter le service Krane localement. Il s'occupera également de sa dépendance redisgraph.
docker-compose up -d
L'image Krane Docker sera prédéfinie automatiquement si elle n'est pas déjà présente sur la machine locale.
Notez que lors de l'exécution docker-compose localement, Krane ne démarrera pas automatiquement le rapport RBAC et le tableau de bord . Au lieu de cela, le conteneur dormira pour 24h par défaut - cette valeur peut être ajustée dans docker-compose.override.yml . EXEC dans un conteneur Krane en cours d'exécution pour exécuter les commandes. docker-compose local montera également Kube Config ( ~/.kube/config ) à l'intérieur du conteneur vous permettant d'exécuter des rapports contre tous les clusters Kubernetes auxquels vous avez déjà accès.
EXEC dans un conteneur Krane en cours d'exécution.
docker-compose exec krane bash Une fois dans le conteneur, vous pouvez commencer à utiliser les commandes krane . Essayez krane -help .
krane -hPour inspecter quels services fonctionnent et les ports associés:
docker-compose ps
Pour arrêter Krane et ses services de dépendance:
docker-compose down
$ krane --help
NAME:
krane
DESCRIPTION:
Kubernetes RBAC static analysis & visualisation tool
COMMANDS:
dashboard Start K8s RBAC dashboard server
help Display global or [command] help documentation
report Run K8s RBAC report
GLOBAL OPTIONS:
-h, --help
Display help documentation
-v, --version
Display version information
-t, --trace
Display backtrace when an error occurs
AUTHOR:
Marcin Ciszak <[email protected]> - Appvia Ltd <appvia.io>
kubectl localPour exécuter un rapport contre un cluster en cours d'exécution, vous devez fournir un contexte kubectl
krane report -k <context>
Vous pouvez également transmettre un indicateur -c <cluster-name> si vous prévoyez d'exécuter l'outil par rapport à plusieurs clusters et index le graphique RBAC séparément pour chaque nom de cluster.
Pour exécuter un rapport contre les fichiers locaux RBAC YAML / JSON, fournissez un chemin de répertoire
krane report -d </path/to/rbac-directory>
Remarque: Krane s'attend à ce que les fichiers suivants (au format YAML ou JSON) soient présents dans le chemin du répertoire spécifié:
Si les politiques de sécurité POD ne sont pas utilisées, vous pouvez contourner les attentes ci-dessus en créant un fichier psp manuellement avec le contenu suivant:
{
"items" : []
} Remarque, PodSecurityPolicy a été déprécié dans Kubernetes v1.21 et supprimé de Kubernetes dans V1.25.
Pour exécuter un rapport à partir d'un conteneur exécuté dans le cluster de Kubernetes
krane report --incluster
Remarque: le compte de service utilisé par Krane aura besoin d'accès aux ressources RBAC. Voir les conditions préalables pour plus de détails.
Pour valider la définition du RBAC comme étape dans le pipeline CI / CD
krane report --ci -d </path/to/rbac-directory>
Remarque: Krane s'attend à ce que certaines congrès de dénomination soient suivies pour les fichiers de ressources RBAC stockés localement. Voir la section ci-dessus. Afin d'exécuter les commandes krane , il est recommandé que CI exécuteur fait référence à Quay.io/appvia/krane:last Docker Image.
Le mode CI est activé par --ci Flag. Krane renverra le code d'état non zéro ainsi que les détails des règles de risque de rupture lorsqu'un ou plusieurs dangers ont été détectés.
Pour afficher l'arborescence des facettes RBAC, le graphique réseau et les derniers résultats du rapport, vous devez d'abord démarrer le serveur de tableau de bord.
krane dashboard
Flag de cluster -c <cluster-name> peut être passé si vous souhaitez exécuter le tableau de bord contre le nom de cluster spécifique. Le tableau de bord recherchera des données liées au nom de cluster spécifié qui est mis en cache sur le système de fichiers.
La commande ci-dessus démarrera le serveur Web local sur le port par défaut 8000 et affichera le lien de tableau de bord.
Krane index RBAC intime dans Redisgraph. Cela nous permet d'interroger efficacement le réseau de dépendances et simplement en utilisant simplement un sous-ensemble de CypherQL pris en charge par Redisgraph.
Les nœuds suivants sont créés dans le graphique pour les objets RBAC pertinents:
Psp - Un nœud PSP contenant des attributs autour de la politique de sécurité du pod. Uniquement applicable lorsque vous travaillez avec K8S <1,25.Rule - Le nœud de règle représente la règle de contrôle d'accès autour des ressources de Kubernetes.Role - Le nœud de rôle représente un rôle donné ou un clusterrole. L'attribut kind définit le type de rôle.Subject - Le sujet représente tous les acteurs possibles dans le cluster ( kind : User, Group et ServiceAccount)Namespace - nœud d'espace de noms de Kubernetes. :SECURITY - Définit un lien entre les nœuds de règle et PSP. Uniquement applicable lorsque vous travaillez avec K8S <1,25.:GRANT - définit un lien entre le rôle et la règle associée à ce rôle.:ASSIGN - définit un lien entre un acteur (sujet) et un rôle / clusterrole donné (nœud de rôle).:RELATION - Définit un lien entre deux nœuds d'actrice (sujet) différents.:SCOPE - définit un lien entre le rôle et les nœuds d'espace de noms.:ACCESS - Définit un lien entre le sujet et les nœuds d'espace de noms.:AGGREGATE - définit un lien entre les clusterroles (un clusterrole agrégats un autre) A-(aggregates)->B:COMPOSITE - Définit un lien entre les clusterroles (une clusterrole peut être agrégée dans un autre) A<-(is a composite of)-B Tous les bords sont bidirectionnels, ce qui signifie que le graphique peut être interrogé dans les deux sens. Seules les exceptions sont les suivantes :AGGREGATE et :COMPOSITE qui sont unidirectionnelles, bien que concernant les mêmes nœuds de bord.
Afin d'interroger directement le graphique, vous pouvez exécuter dans un conteneur redisgraph en cours d'exécution, démarrer redis-cli et exécuter vos requêtes arbitraires. Suivez les instructions officielles pour des exemples de commandes.
Vous pouvez également interroger le graphique de Krane Console. D'abord l'exécution dans l'exécution du conteneur Krane , puis
# Start Krane console - this will open interactive ruby shell with Krane code preloaded
console
# Instantiate Graph client
graph = Krane :: Clients :: RedisGraph . client cluster : 'default'
# Run arbitrary CypherQL query against indexed RBAC Graph
res = graph . query ( %Q(
MATCH (r:Rule {resource: "configmaps", verb: "update"})<-[:GRANT]-(ro:Role)<-[:ASSIGN]-(s:Subject)
RETURN s.kind as subject_kind, s.name as subject_name, ro.kind as role_kind, ro.name as role_name) )
# Print the results
res . print_resultset # Results...
+----------------+--------------------------------+-----------+------------------------------------------------+
| subject_kind | subject_name | role_kind | role_name |
+----------------+--------------------------------+-----------+------------------------------------------------+
| ServiceAccount | bootstrap-signer | Role | system:controller:bootstrap-signer |
| User | system:kube-controller-manager | Role | system::leader-locking-kube-controller-manager |
| ServiceAccount | kube-controller-manager | Role | system::leader-locking-kube-controller-manager |
| User | system:kube-scheduler | Role | system::leader-locking-kube-scheduler |
| ServiceAccount | kube-scheduler | Role | system::leader-locking-kube-scheduler |
+----------------+--------------------------------+-----------+------------------------------------------------+
Remarque: l'exemple de requête ci-dessus sélectionnera tous les sujets avec des rôles / clusterroles attribués accordant l'accès aux update configmaps .
Les règles de risque RBAC sont définies dans le dossier des règles. La structure de chaque règle est largement explicite. L'ensemble intégré peut être élargi / remplacé en ajoutant des règles personnalisées supplémentaires au fichier de règles Cutom.
Les macros sont des «conteneurs» pour un ensemble d'attributs communs / partagés et référencés par une ou plusieurs règles de risque. Si vous choisissez d'utiliser une macro dans une règle de risque donnée, vous devez le référencer par nom, par exemple macro: <macro-name> . Notez que les attributs définis dans macro référencée auront la priorité sur les mêmes attributs définis au niveau des règles.
La macro peut contenir l'un des attributs suivants:
query - Redegraph Query. A la priorité sur template . Exige que writer soit défini.writer - L'écrivain est une expression Ruby utilisée pour formater l'ensemble de résultats query . L'écrivain a la priorité sur template .template - Nom de modèle de requête / écrivain intégré. Si query & writer ne sont pas spécifiés, le générateur de requête choisi sera utilisé avec l'écrivain assorti. La règle peut contenir l'un des attributs suivants:
id [requis] L'ID de règle est un identifiant de règle unique.
group_title [requis] Titre s'appliquant à tous les éléments qui relèvent de cette vérification des risques.
severity [requise] Gravité, comme un de: Danger ,: avertissement ,: info.
info [requises] Informations textuelles sur la vérification et les suggestions sur la façon d'atténuer le risque.
query [conditonal] redisgraph requête.
template . Exige que writer soit défini. writer [Conditonal] L'écrivain est une expression Ruby utilisée pour formater l'ensemble de résultats de requête.
template . Nécessite la définition query . template [conditonal] Nom de modèle de requête / écrivain intégré. Si query & writer ne sont pas spécifiés, le générateur de requête choisi sera utilisé avec l'écrivain assorti.
Certains modèles intégrés nécessitent l'attribut match_rules à spécifier au niveau des règles individuelles afin de créer une requête correcte. Modèles qui l'exigent actuellement:
match_rules . La requête graphique générée renvoie les colonnes suivantes: match_rules [conditonal] requis lorsque template s'appuie sur les règles de correspondance afin de créer une requête.
match_rules :
- resources : ['cronjobs']
verbs : ['update'] custom_params [Facultatif] Liste des paires de valeurs clés personnalisées à évaluer et remplacés dans une query de règle et une représentation writer .
custom_params :
- attrA : valueA
- attrB : valueB{{attrA}} et {{attrB}} seront remplacés respectivement par valueA et valueB . threshold [facultatif] Valeur numérique. Lorsqu'il est défini, cela deviendra disponible en tant que modèle d'emplacements de place {{threshold}} dans l'expression writer .
macro [facultatif] Référence aux paramètres communs définis dans une macro nommée.
disabled [Facultatif] Lorsqu'il est défini sur true , il désactivera la règle donnée et l'exclura de l'évaluation. Par défaut, toutes les règles sont activées.
- id : verbose-rule-example
group_title : Example rule
severity : :danger
info : Risk description and instructions on how to mitigate it goes here
query : |
MATCH
(s:Subject)-[:ACCESS]->(ns:Namespace)
WHERE
NOT s.name IN {{whitelist_subject_names}}
RETURN
s.kind as subject_kind,
s.name as subject_name,
COLLECT(ns.name) as namespace_names
ORDER BY
subject_kind,
subject_name,
namespace_names DESC
threshold : 2
writer : |
if result.namespace_names.count > {{threshold}}
"#{result.subject_kind} #{result.subject_name} can access namespaces: #{result.namespace_names.join(', ')}"
end
disabled : true L'exemple ci-dessus définit explicitement une query graphique qui est utilisée pour évaluer le risque RBAC et une expression writer utilisée pour formater l'ensemble de résultats de la requête. La requête sélectionne simplement tous Subjects (à l'exclusion de la liste blanche) et Namespaces auxquels ils ont accès. Notez que l'ensemble de résultats ne comprendra que Subjects ayant accès à plus de 2 espaces de noms (valeur threshold remarquée là-bas?). L'expression du dernier writer sera capturée en tant que sortie de l'élément de résultat formaté.
writer peut accéder à l'élément SET de résultat via l'objet result avec des méthodes correspondant aux éléments renvoyés par la requête, par exemple result.subject_kind , result.subject_name etc.
Note:
{{threshold}} L'espace que l'expression writer sera remplacée par la valeur de mot-clé de threshold de la règle.{{whitelist_subject_names}} représente un champ personnalisé qui sera interpolé avec des valeurs de liste blanche définies pour un id de règle donné. Si un nom de champ d'espace réservé n'est pas défini dans la liste blanche, elle sera remplacée par un tableau vide [''] par défaut. En savoir plus sur la liste blanche ci-dessous. Les modèles intégrés simplifient considérablement la définition de la règle de risque, cependant, ils sont conçus pour extraire un type d'informations spécifiques et peuvent ne pas être un bon choix pour vos règles personnalisées. Si vous vous retrouvez à réutiliser la même query ou les mêmes expressions writer sur plusieurs règles, vous devriez envisager de les extraire à une macro et de les référencer dans vos règles personnalisées pour les sécher.
- id : risky-any-verb-secrets
group_title : Risky Roles/ClustersRoles allowing all actions on secrets
severity : :danger
info : Roles/ClusterRoles allowing all actions on secrets. This might be dangerous. Review listed Roles!
template : risky-role
match_rules :
- resources : ['secrets']
verbs : ['*'] L'exemple ci-dessus montre l'une des règles intégrées. Il fait référence à un modèle risky-role qui, lors du traitement, élargira la règle en injectant les expressions query et writer avant les déclencheurs de l'évaluation des règles. match_rules sera utilisé pour créer une requête de match appropriée.
La liste blanche facultative contient un ensemble de noms d'attributs définis personnalisés et de valeurs respectives (listée blanche).
Les noms d'attribut et leurs valeurs sont arbitraires. Ils sont définis dans le fichier de liste blanche et divisés en trois sections distinctes:
global de niveau supérieur. Les attributs personnalisés définis ici s'appliqueront à toutes les règles de risque quel que soit le nom du cluster.common - Custom seront portée à id de règle de risque spécifique quel que soit le nom du cluster.cluster (avec la liste imbriquée des noms de cluster) - Les attributs personnalisés s'appliqueront à id de règle de risque spécifique pour un nom de cluster donné. Chaque règle de risque, lors de l'évaluation, tentera d'interpoler tous les espaces réservés des paramètres utilisés dans la query , par exemple {{your_whitelist_attribute_name}} . Si un nom de paramètre d'espace réservé (c'est-à-dire un nom entre les supports à double boucle) correspond à l'un des noms d'attribut de liste blanche pour cet id de règle de risque, il sera remplacé par sa valeur calculée. Si aucune valeur n'est trouvée pour un espace réservé donné, il sera remplacé par [''] .
Exemple de liste blanche ci-dessous produit la placeholder-key => value pour une règle de risque avec l'attribut d' id correspondant à la valeur "Some-Risk-Rule-ID"
{{whitelist_role_names}} => ['acp:prometheus:operator']
{{whitelist_subject_names}} => ['privileged-psp-user', 'another-user']
Les clés de l'espace réservé ci-dessus, lorsqu'elles sont utilisées dans les requêtes de graphique personnalisées, seront remplacées par leurs valeurs respectives lors de l'évaluation des règles de risque.
Exemple:
---
rules :
global : # global scope - applies to all risk rule and cluster names
whitelist_role_names : # custom attribute name
- acp:prometheus:operator # custom attribute values
common : # common scope - applies to specific risk rule id regardless of cluster name
some-risk-rule-id : # this corresponds to risk rule id defined in config/rules.yaml
whitelist_subject_names : # custom attribute name
- privileged-psp-user # custom attribute values
cluster : # cluster scope - applies to speciifc risk rule id and cluster name
default : # example cluster name
some-risk-rule-id : # risk rule id
whitelist_subject_names : # custom attribute nane
- another-user # custom attribute values Krane peut être déployé facilement sur une clusters Kubernetes locale ou éloignée.
L'espace de noms Kubernetes, le compte de service ainsi que le RBAC approprié doivent être présents dans le cluster. Voir les conditions préalables à référence.
Le point d'entrée de Krane par défaut exécute BIN / in-cluster run qui attend que l'instance Redisgraph soit disponible avant de démarrer la boucle de rapport RBAC et le serveur Web de tableau de bord .
Vous pouvez contrôler certains aspects de l'exécution en grappe avec les variables d'environnement suivantes:
KRANE_REPORT_INTERVAL - définit l'intervalle en secondes pour le rapport d'analyse statique RBAC exécuté. Par défaut: 300 (en secondes, c'est-à-dire 5 minutes).KRANE_REPORT_OUTPUT - Définit le format de sortie du rapport de risque RBAC. Valeurs possibles :json , :yaml , :none . Par défaut :: :json .Avant de commencer, vous aurez besoin des outils suivants:
Installez le graphique de la barre:
$ helm repo add appvia https://appvia.github.io/krane
$ helm repo update
$ helm install krane appvia/krane --namespace krane --create-namespaceVoir les valeurs.yaml Fichier pour plus de détails sur d'autres options et paramètres établis.
kubectl create
--context < docker-desktop >
--namespace krane
-f k8s/redisgraph-service.yaml
-f k8s/redisgraph-deployment.yaml
-f k8s/krane-service.yaml
-f k8s/krane-deployment.yamlNotez que le service de tableau de bord Krane n'est pas exposé par défaut!
kubectl port-forward svc/krane 8000
--context= < docker-desktop >
--namespace=krane
# Open Krane dashboard at http://localhost:8000Vous pouvez trouver l'exemple de manifestes de déploiement dans le répertoire K8S.
Modifiez les manifestes selon les besoins pour vos déploiements en vous assurant de référencer la version correcte de l'image Krane Docker dans son fichier de déploiement. Voir Krane Docker Registry pour les balises disponibles, ou utilisez simplement latest .
Si votre cluster K8S est livré avec la prise en charge du contrôleur Compose-on-Kubernetes intégré ( docker-desktop le prend en charge par défaut), vous pouvez déployer Krane et ses dépendances avec une seule commande Docker Stack:
docker stack deploy
--orchestrator kubernetes
--namespace krane
--compose-file docker-compose.yml
--compose-file docker-compose.k8s.yml kraneRemarque: assurez-vous que votre contexte Kube actuel est défini correctement avant d'exécuter la commande ci-dessus!
La pile d'application doit être maintenant déployée dans un cluster Kubernetes et tous les services prêts et exposés. Notez que Krane démarrera automatiquement sa boucle de rapport et son serveur de tableau de bord.
docker stack services --orchestrator kubernetes --namespace krane kraneLa commande ci-dessus produira la sortie suivante:
ID NAME MODE REPLICAS IMAGE PORTS
0de30651-dd5 krane_redisgraph replicated 1/1 redislabs/redisgraph:1.99.7 *:6379->6379/tcp
aa377a5f-62b krane_krane replicated 1/1 quay.io/appvia/krane:latest *:8000->8000/tcp
Vérifiez votre posture de sécurité Kubernetes Cluster RBAC en visitant http: // localhost: 8000.
Notez que pour les déploiements de cluster à distance, vous devrez probablement d'abord le service de Krane
kubectl --context=my-remote-cluster --namespace=krane port-forward svc/krane 8000Pour supprimer la pile
docker stack rm krane
--orchestrator kubernetes
--namespace kraneKrane vous informera des anomalies détectées de gravité moyenne et élevée via son intégration de mou.
Pour activer les notifications, spécifiez Slack webhook_url & channel dans le fichier config / config.yaml, ou définissez également les variables d'environnement SLACK_WEBHOOK_URL et SLACK_CHANNEL . Les variables d'environnement auront la priorité sur les valeurs de fichiers de configuration.
Cette section décrit les étapes pour permettre le développement local.
Installez les dépendances de code Krane avec
./bin/setup Krane dépend du redisgraph. docker-compose est le moyen le plus rapide de faire fonctionner les dépendances de Krane localement.
docker-compose up -d redisgraphPour inspecter le service Redisgraph est en place:
docker-compose psPour arrêter les services:
docker-compose downÀ ce stade, vous devriez être en mesure de modifier la base de code Krane et les résultats de test en invoquant des commandes dans Shell local.
$ ./bin/krane --help # to get help
$ ./bin/krane report -k docker-desktop # to generate your first report for
# local docker-desktop k8s cluster
...Pour activer le mode de développement local du tableau de bord UI
$ cd dashboard
$ npm install
$ npm startCela démarrera automatiquement le serveur de tableau de bord, ouvrira le navigateur par défaut et surveiller les modifications des fichiers source.
Krane est préconfiguré pour améliorer l'expérience des développeurs avec Skaffold. Itération sur le projet et valider l'application en exécutant la pile entière dans le cluster Kubernetes local ou distant est devenu plus facile. Code Hot-Reload permet à des modifications locales de se propager automatiquement au conteneur en cours d'exécution pour un cycle de vie de développement plus rapide.
skaffold dev --kube-context docker-desktop --namespace krane --port-forwardExécutez des tests localement avec
bundle exec rspecNous accueillons toutes les contributions de la communauté! Jetez un œil à notre guide de contribution pour plus d'informations sur la façon de commencer. Si vous utilisez Krane , trouvez-le utile ou si vous êtes généralement intéressé par la sécurité de Kubernetes, veuillez nous en informer en mettant en vedette et en regardant ce dépôt. Merci!
Rejoignez la discussion sur notre canal communautaire.
Krane est un projet communautaire et nous accueillons vos contributions. Pour signaler un bogue, suggérez une amélioration ou demandez une nouvelle fonctionnalité, veuillez ouvrir un problème GitHub. Reportez-vous à notre guide de contribution pour plus d'informations sur la façon dont vous pouvez vous aider.
Voir notre feuille de route pour plus de détails sur nos plans pour le projet.
Auteur: Marcin Ciszak [email protected]
Copyright (c) 2019-2020 Appvia Ltd
Ce projet est distribué sous la licence Apache, version 2.0.