
Strumento per l'analisi statica e la visualizzazione di RBAC di Kubernetes
Analisi RBAC di Kubernetes resa semplice
Krane è un semplice strumento di analisi statica RBAC per Kubernetes. Identifica potenziali rischi di sicurezza nella progettazione RBAC di K8s e fornisce suggerimenti su come mitigarli. La dashboard di Krane presenta lo stato attuale della sicurezza RBAC e consente di navigare attraverso la sua definizione.
Puoi iniziare con Krane installandolo tramite chart Helm nel tuo cluster Kubernetes di destinazione o eseguendolo localmente con Docker.
Si presume che tu abbia Helm CLI installato sulla tua macchina.```sh $ helm repo add appvia https://appvia.github.io/krane $ helm repo update $ helm install krane appvia/krane --namespace krane --create-namespace
Segui l'output dell'installazione del chart Helm su come eseguire il port-forward del dashboard di Krane.
### Esecuzione con Docker
Si assume che tu abbia [docker](https://docs.docker.com/get-docker/) in esecuzione sulla tua macchina locale. Installa [docker-compose](https://docs.docker.com/compose/install/#install-compose) se non l'hai già fatto.
Krane dipende da RedisGraph. Lo stack `docker-compose` definisce tutto il necessario per creare ed eseguire il servizio _Krane_ localmente. Si occuperà anche della dipendenza [RedisGraph](https://oss.redislabs.com/redisgraph/).```
docker-compose up -d
_L'immagine docker di Krane verrà pre-costruita automaticamente se non già presente sulla macchina locale.
Nota che quando si esegue docker-compose localmente, Krane non avvierà RBAC report e dashboard automaticamente. Invece, il container rimarrà in attesa per 24h di default - questo valore può essere modificato in docker-compose.override.yml. Entra in un container Krane in esecuzione per eseguire comandi. Il docker-compose locale monterà anche il kube config (~/.kube/config) all'interno del container, permettendoti di eseguire report su qualsiasi cluster Kubernetes a cui hai già accesso.
Entra in un container Krane in esecuzione.```sh docker-compose exec krane bash
Una volta nel contenitore, puoi iniziare a usare i comandi `krane`. Prova `krane -help`.```sh
krane -h
Per ispezionare quali servizi sono in esecuzione e le porte associate:``` docker-compose ps
Per fermare _Krane_ e i suoi servizi dipendenti:```
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>
### Genera report RBAC
#### Con contesto `kubectl` locale
Per eseguire un report su un cluster in esecuzione è necessario fornire un contesto _kubectl_```
krane report -k <context>
You may also pass -c <cluster-name> flag if you plan to run the tool against multiple clusters and index RBAC graph separately for each cluster name.
Per eseguire un report su file yaml/json RBAC locali, fornisci un percorso di directory.``` krane report -d </path/to/rbac-directory>
NOTA: _Krane_ si aspetta che i seguenti file (in formato YAML o JSON) siano presenti nel percorso di directory specificato:
- psp
- roles
- clusterroles
- rolebindings
- clusterrolebindings
Se le Pod Security Policies non sono in uso, puoi bypassare l'aspettativa precedente creando manualmente un file `psp` con il seguente contenuto:```json
{
"items": []
}
Nota, PodSecurityPolicy è stato deprecato in Kubernetes v1.21 e rimosso da Kubernetes in v1.25.
Per eseguire un report da un container in esecuzione in un cluster Kubernetes``` krane report --incluster
NOTE: Il service account utilizzato da _Krane_ richiederà l'accesso alle risorse RBAC. Vedi [Prerequisiti](https://github.com/appvia/krane/blob/HEAD/k8s/one-time/prerequisites.yaml) per i dettagli.
#### In pipeline CI/CD
Per validare la definizione RBAC come passaggio in una pipeline CI/CD```
krane report --ci -d </path/to/rbac-directory>
NOTA: Krane richiede che venga seguita una specifica convenzione di nomenclatura per i file delle risorse RBAC memorizzati localmente. Vedere la sezione sopra. Per eseguire i comandi krane si consiglia che l'esecutore CI faccia riferimento all'immagine docker quay.io/appvia/krane:latest.
La modalità CI è abilitata dal flag --ci. Krane restituirà un codice di uscita diverso da zero insieme ai dettagli delle regole di rischio violate quando vengono rilevati uno o più pericoli.
Per visualizzare l'albero delle facet RBAC, il grafo di rete e gli ultimi risultati dei report è necessario prima avviare il server della dashboard.``` krane dashboard
Cluster flag `-c <nome-cluster>` può essere passato se si desidera eseguire la dashboard su un nome cluster specifico. La dashboard cercherà i dati relativi al nome cluster specificato che sono memorizzati nella cache del file system.
Il comando sopra avvierà un server web locale sulla porta predefinita `8000` e mostrerà il link della dashboard.
## Architettura
### Dati RBAC indicizzati in un database grafico locale
_Krane_ indicizza le entità RBAC in RedisGraph. Questo ci consente di interrogare la rete di dipendenze in modo efficiente e semplice utilizzando un sottoinsieme di [CypherQL](https://oss.redislabs.com/redisgraph/cypher_support/) supportato da [RedisGraph](https://oss.redislabs.com/redisgraph/).
#### Schema

#### Nodi
I seguenti nodi vengono creati nel grafico per gli oggetti RBAC pertinenti:
* `Psp` - Un nodo PSP contenente attributi relativi alla pod security policy. Applicabile solo quando si lavora con K8s < 1.25.
* `Rule` - Il nodo Rule rappresenta una regola di controllo accessi relativa alle risorse Kubernetes.
* `Role` - Il nodo Role rappresenta un dato Role o ClusterRole. L'attributo `kind` definisce il tipo di ruolo.
* `Subject` - Subject rappresenta tutti i possibili attori nel cluster (`kind`: User, Group e ServiceAccount)
* `Namespace` - Nodo Namespace di Kubernetes.
#### Archi
* `:SECURITY` - Definisce un collegamento tra nodi Rule e Psp. Applicabile solo quando si lavora con K8s < 1.25.
* `:GRANT` - Definisce un collegamento tra Role e Rule associati a quel ruolo.
* `:ASSIGN` - Definisce un collegamento tra un Attore (Subject) e un dato Role/ClusterRole (nodo Role).
* `:RELATION` - Definisce un collegamento tra due diversi nodi Attore (Subject).
* `:SCOPE` - Definisce un collegamento tra nodi Role e Namespace.
* `:ACCESS` - Definisce un collegamento tra nodi Subject e Namespace.
* `:AGGREGATE` - Definisce un collegamento tra ClusterRole (un ClusterRole aggrega un altro) `A-(aggregates)->B`
* `:COMPOSITE` - Definisce un collegamento tra ClusterRole (un ClusterRole può essere aggregato in un altro) `A<-(is a composite of)-B`
Tutti gli archi sono bidirezionali, il che significa che il grafico può essere interrogato in entrambe le direzioni.
Le uniche eccezioni sono le relazioni `:AGGREGATE` e `:COMPOSITE`, che sono unidirezionali, sebbene riguardino gli stessi nodi intermedi.
#### Interrogazione del grafico
Per interrogare direttamente il grafico, puoi eseguire un exec in un container `redisgraph` in esecuzione, avviare `redis-cli` ed eseguire le tue query arbitrarie. Segui le [istruzioni](https://oss.redislabs.com/redisgraph/) ufficiali per esempi di [comandi](https://oss.redislabs.com/redisgraph/commands/).
Puoi anche interrogare il grafico dalla console di _Krane_. Prima esegui un exec nel container _Krane_ in esecuzione, poi```ruby
# 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
INPUT:```
+----------------+--------------------------------+-----------+------------------------------------------------+ | 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 | +----------------+--------------------------------+-----------+------------------------------------------------+
Nota: La query di esempio sopra selezionerà tutti i Soggetti con Ruoli/ClusterRoles assegnati che concedono accesso a `update configmaps`.
## Configurazione
### Regole di Rischio RBAC
Le regole di rischio RBAC sono definite nel file [Rules](https://github.com/appvia/krane/blob/HEAD/config/rules.yaml). La struttura di ciascuna regola è in gran parte autoesplicativa.
Il set integrato può essere espanso/sostituito aggiungendo regole personalizzate extra al file [Custom Rules](https://github.com/appvia/krane/blob/HEAD/config/custom-rules.yaml).
#### Macro delle Regole di Rischio
Le macro sono "contenitori" per un insieme di attributi comuni/condivisi e vengono referenziate da una o più regole di rischio. Se scegli di utilizzare una macro in una determinata regola di rischio, devi referenziarla per nome, ad es. `macro: <nome-macro>`. Nota che gli attributi definiti nella macro referenziata avranno precedenza rispetto agli stessi attributi definiti a livello di regola.
Una macro può contenere uno qualsiasi dei seguenti attributi:
- `query` - [Query RedisGraph](#querying-the-graph). Ha precedenza su `template`. Richiede che sia definito `writer`.
- `writer` - Writer è un'espressione Ruby utilizzata per formattare il set di risultati di `query`. Writer ha precedenza su `template`.
- `template` - Nome del template built-in di query/writer. Se `query` e `writer` non sono specificati, verrà utilizzato il generatore di query scelto assieme al writer corrispondente.
#### Attributi delle Regole di Rischio
Una regola può contenere uno qualsiasi dei seguenti attributi:
- `id` [Obbligatorio] L'id della regola è un identificatore univoco.
- `group_title` [Obbligatorio] Titolo applicabile a tutti gli elementi che rientrano in questo controllo di rischio.
- `severity` [Obbligatorio] Severità, come uno tra :danger, :warning, :info.
- `info` [Obbligatorio] Informazioni testuali sul controllo e suggerimenti su come mitigare il rischio.
- `query` [Condizionale] [Query RedisGraph](#querying-the-graph).
- Ha precedenza su `template`. Richiede che sia definito `writer`.
- `writer` [Condizionale] Writer è un'espressione Ruby utilizzata per formattare il set di risultati di query.
- Writer ha precedenza su `template`. Richiede che sia definita `query`.
- `template` [Condizionale] Nome del template built-in di query/writer. Se `query` e `writer` non sono specificati, verrà utilizzato il generatore di query scelto assieme al writer corrispondente.
- Alcuni template built-in richiedono che l'attributo `match_rules` sia specificato a livello di singola regola per costruire la query corretta. Template che attualmente lo richiedono:
- **_risky-role_** - Costruisce una query di grafo multi-match basata sulle regole di accesso specificate da `match_rules`. La query di grafo generata restituisce le seguenti colonne:
- role_name
- role_kind
- namespace_name (viene restituito un _array_ se vengono restituiti più elementi)
- `match_rules` [Condizionale] Richiesto quando `template` si basa su regole di match per costruire una query.
- Esempio:
```yaml
match_rules:
- resources: ['cronjobs']
verbs: ['update']
```
Gli attributi e i valori seguono la [specifica del ruolo RBAC di Kubernetes](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-examples).
- `custom_params` [Opzionale] Elenco di coppie chiave-valore personalizzate da valutare e sostituire nella rappresentazione di `query` e `writer` della regola.
- Esempio:
```yaml
custom_params:
- attrA: valueA
- attrB: valueB
```
I placeholder del template per le chiavi sopra `{{attrA}}` e `{{attrB}}` verranno sostituiti con `valueA` e `valueB` rispettivamente.
- `threshold` [Opzionale] Valore numerico. Quando definito, diventa disponibile come placeholder del template `{{threshold}}` nell'espressione `writer`.
- `macro` [Opzionale] Riferimento a parametri comuni definiti in una macro nominata.
- `disabled` [Opzionale] Se impostato a `true`, disabilita la regola data e la esclude dalla valutazione.
Per impostazione predefinita tutte le regole sono abilitate.
#### Esempi di Regole di Rischio
##### Espressione esplicita di query & writer```yaml
- 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'esempio sopra definisce esplicitamente una query del grafo utilizzata per valutare il rischio RBAC, e un'espressione writer usata per formattare il set di risultati della query. La query seleziona semplicemente tutti i Subjects (esclusi quelli in whitelist) e i Namespaces a cui hanno accesso. Nota che il set di risultati includerà solo i Subjects che hanno accesso a più di 2 Namespaces (Hai notato il valore threshold?). L'espressione del writer finale verrà catturata come output dell'elemento del risultato formattato.
writer può accedere all'elemento del set di risultati tramite l'oggetto result con metodi che corrispondono agli elementi restituiti dalla query, ad es. result.subject_kind, result.subject_name ecc.
Nota:
{{threshold}} nell'espressione writer verrà sostituito dal valore della parola chiave threshold della regola.{{whitelist_subject_names}} rappresenta un campo personalizzato che verrà interpolato con i valori della Whitelist definiti per un dato id della regola. Se un nome di campo segnaposto non è definito nella whitelist, verrà sostituito con un array vuoto [''] per impostazione predefinita. Leggi di più sulla whitelist qui sotto.I template integrati semplificano notevolmente la definizione delle regole di rischio, tuttavia sono progettati per estrarre un tipo specifico di informazioni e potrebbero non essere adatti per le tue regole personalizzate. Se ti ritrovi a riutilizzare le stesse espressioni query o writer in più regole, dovresti considerare di estrarle in una macro e farvi riferimento nelle tue regole personalizzate per non ripeterti (DRY).```yaml
L'esempio sopra mostra una delle regole integrate. Fa riferimento al modello `risky-role` che, durante l'elaborazione, espanderà la regola iniettando le espressioni `query` e `writer` prima che vengano attivati i trigger di valutazione della regola. `match_rules` verrà utilizzato per costruire la query di corrispondenza appropriata.
### Whitelist dei Rischi RBAC
La whitelist opzionale contiene un insieme di nomi di attributi personalizzati e rispettivi valori (whitelisted).
#### Attributi della whitelist
I nomi degli attributi e i loro valori sono arbitrari. Sono definiti nel file [Whitelist](https://github.com/appvia/krane/blob/HEAD/config/whitelist.yaml) e suddivisi in tre sezioni separate:
- `global` - Ambito di livello superiore. Gli attributi personalizzati definiti qui si applicheranno a tutte le Regole di Rischio indipendentemente dal nome del cluster.
- `common` - Gli attributi personalizzati saranno limitati a uno specifico `id` di Regola di Rischio indipendentemente dal nome del cluster.
- `cluster` (con elenco annidato di nomi di cluster) - Gli attributi personalizzati si applicheranno a uno specifico `id` di Regola di Rischio per un dato nome di cluster.
Ogni [Regola di Rischio](#rbac-risk-rules), durante la valutazione, tenterà di interpolare tutti i segnaposto dei parametri utilizzati nella `query`, ad es. `{{your_whitelist_attribute_name}}`. Se il nome di un parametro segnaposto (cioè un nome tra le doppie parentesi graffe) corrisponde a uno qualsiasi dei nomi di attributi whitelistati per quella `id` di Regola di Rischio, verrà sostituito con il suo valore calcolato.
Se non vengono trovati valori per un dato segnaposto, verrà sostituito con `['']`.
#### Esempi di whitelist
L'esempio di whitelist seguente produce la seguente mappatura `placeholder-key => value` per una [Regola di Rischio](#rbac-risk-rules) con attributo `id` il cui valore corrisponde a _"some-risk-rule-id"_```
{{whitelist_role_names}} => ['acp:prometheus:operator']
{{whitelist_subject_names}} => ['privileged-psp-user', 'another-user']
Le chiavi segnaposto sopra, quando utilizzate nelle query di grafo personalizzate, verranno sostituite con i rispettivi valori durante la valutazione della Risk Rule.
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
## Distribuzione Kubernetes
_Krane_ può essere distribuito facilmente su cluster Kubernetes locali o remoti.
### Prerequisiti K8s
Il namespace Kubernetes, il service account insieme al RBAC appropriato devono essere presenti nel cluster. Vedi i [Prerequisiti](https://github.com/appvia/krane/blob/HEAD/k8s/one-time/prerequisites.yaml) come riferimento.
Il punto di ingresso predefinito di _Krane_ esegue [bin/in-cluster-run](https://github.com/appvia/krane/blob/HEAD/bin/in-cluster-run) che attende che l'istanza RedisGraph diventi disponibile prima di avviare il ciclo di _report_ RBAC e il server web _dashboard_.
Puoi controllare alcuni aspetti dell'esecuzione nel cluster con le seguenti variabili d'ambiente:
* `KRANE_REPORT_INTERVAL` - Definisce l'intervallo in secondi per l'esecuzione del report di analisi statica RBAC. Predefinito: `300` (in secondi, ovvero 5 minuti).
* `KRANE_REPORT_OUTPUT` - Definisce il formato di output del report di rischio RBAC. Valori possibili `:json`, `:yaml`, `:none`. Predefinito: `:json`.
### Cluster K8s Locale o Remoto
#### Helm Chart
Prima di iniziare, avrai bisogno dei seguenti strumenti:
* [Helm CLI](https://helm.sh/docs/intro/install/)
Installa il chart Helm:```sh
$ helm repo add appvia https://appvia.github.io/krane
$ helm repo update
$ helm install krane appvia/krane --namespace krane --create-namespace
Vedi il file values.yaml per i dettagli delle altre opzioni e parametri impostabili.
kubectl create
--context
--namespace krane
-f k8s/redisgraph-service.yaml
-f k8s/redisgraph-deployment.yaml
-f k8s/krane-service.yaml
-f k8s/krane-deployment.yaml
Nota che il servizio dashboard di _Krane_ non è esposto di default!```sh
kubectl port-forward svc/krane 8000 \
--context=<docker-desktop> \
--namespace=krane
# Open Krane dashboard at http://localhost:8000
Puoi trovare i manifest di deployment di esempio nella directory k8s.
Modifica i manifest secondo le necessità dei tuoi deployment, assicurandoti di fare riferimento alla versione corretta dell'immagine docker di Krane nel suo file di deployment. Consulta il Registro Docker di Krane per i tag disponibili, o usa semplicemente latest.
Se il tuo cluster K8s supporta il controller Compose-on-Kubernetes integrato (docker-desktop lo supporta per impostazione predefinita), allora puoi distribuire Krane e le sue dipendenze con un singolo comando docker stack:```sh
docker stack deploy
--orchestrator kubernetes
--namespace krane
--compose-file docker-compose.yml
--compose-file docker-compose.k8s.yml krane
Nota: assicurati che il tuo attuale contesto kube sia impostato correttamente prima di eseguire il comando sopra!
Lo Stack applicativo dovrebbe ora essere distribuito su un cluster Kubernetes e tutti i servizi pronti ed esposti. Nota che _Krane_ avvierà automaticamente il suo ciclo di report e il server del dashboard.```sh
docker stack services --orchestrator kubernetes --namespace krane krane
Il comando sopra produrrà il seguente output:``` 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
Controlla la postura di sicurezza RBAC del tuo cluster Kubernetes visitando http://localhost:8000.
Nota che per deployment su cluster remoti probabilmente dovrai prima effettuare il port-forward del servizio _Krane_```sh
kubectl --context=my-remote-cluster --namespace=krane port-forward svc/krane 8000
Per eliminare lo Stack```sh
docker stack rm krane
--orchestrator kubernetes
--namespace krane
## Notifiche
Krane ti notificherà le anomalie rilevate di media e alta gravità tramite la sua integrazione Slack.
Per abilitare le notifiche, specifica `webhook_url` e `channel` di Slack nel file [config/config.yaml](https://github.com/appvia/krane/blob/HEAD/config/config.yaml), oppure imposta entrambe le variabili d'ambiente `SLACK_WEBHOOK_URL` e `SLACK_CHANNEL`. Le variabili d'ambiente avranno la precedenza sui valori del file di configurazione.
## Sviluppo Locale
Questa sezione descrive i passaggi per abilitare lo sviluppo locale.
### Impostazione
Installa le dipendenze del codice di _Krane_ con```sh
./bin/setup
Krane dipende da RedisGraph. docker-compose è il modo più rapido per far funzionare le dipendenze di Krane localmente.```sh
docker-compose up -d redisgraph
Per verificare che il servizio RedisGraph sia attivo:```sh
docker-compose ps
Per fermare i servizi:```sh docker-compose down
### Sviluppo
A questo punto dovresti essere in grado di modificare il codebase di _Krane_ e testare i risultati eseguendo comandi nella shell locale.```sh
$ ./bin/krane --help # to get help
$ ./bin/krane report -k docker-desktop # to generate your first report for
# local docker-desktop k8s cluster
...
Per abilitare la modalità di sviluppo locale dell'interfaccia Dashboard```sh $ cd dashboard $ npm install $ npm start
Questo avvierà automaticamente il server Dashboard, aprirà il browser predefinito e monitorerà le modifiche ai file sorgente.
_Krane_ è preconfigurato per una migliore esperienza di sviluppo con [Skaffold](https://skaffold.dev/). Iterare sul progetto e convalidare l'applicazione eseguendo l'intero stack in un cluster Kubernetes locale o remoto è diventato più semplice.
Il ricaricamento a caldo del codice consente di propagare automaticamente le modifiche locali al container in esecuzione per un ciclo di sviluppo più rapido.```sh
skaffold dev --kube-context docker-desktop --namespace krane --port-forward
Esegui i test localmente con```sh bundle exec rspec
## Contribuire a Krane
Accogliamo con favore qualsiasi contributo dalla community! Dai un'occhiata alla nostra guida per [contribuire](https://github.com/appvia/krane/blob/HEAD/CONTRIBUTING.md) per maggiori informazioni su come iniziare. Se utilizzi _Krane_, lo trovi utile o sei generalmente interessato alla sicurezza di Kubernetes, faccelo sapere **stellando** e **seguendo** questo repository. Grazie!
## Partecipa
Unisciti alla discussione sul nostro [canale della community](https://www.appvia.io/join-the-appvia-community).
Krane è un progetto della community e accogliamo i tuoi contributi. Per segnalare un bug, suggerire un miglioramento o richiedere una nuova funzionalità, apri una issue su GitHub. Fai riferimento alla nostra guida per [contribuire](https://github.com/appvia/krane/blob/HEAD/CONTRIBUTING.md) per maggiori informazioni su come puoi aiutare.
## Roadmap
Consulta la nostra [Roadmap](https://github.com/appvia/krane/projects/1) per dettagli sui nostri piani per il progetto.
## Licenza
Autore: Marcin Ciszak <[email protected]>
Copyright (c) 2019-2020 [Appvia Ltd](https://appvia.io)
Questo progetto è distribuito sotto la [Licenza Apache, Versione 2.0](https://github.com/appvia/krane/blob/HEAD/LICENSE).