# Kong

Ref: https://docs.konghq.com/1.0.x/admin-api/

![schema](kong/schema.png "Schema entità principali")

## Servizio (https://docs.konghq.com/1.0.x/admin-api/# service-object)
Il "service" risponde al significato intuitivo di servizio: di fatto definisce *cosa* Kong deve "proxare". Proxa sempre un **upstream** che può essere "virtuale" vedi dopo, oppure è un servizio "reale" ed esterno (Microservice/tomcat/ o altro)

## Rotte (https://docs.konghq.com/1.0.x/admin-api/# route-object)
«Route entities define rules to match client requests. Each Route is associated with a Service, and a Service may have multiple Routes associated to it. Every request matching a given Route will be proxied to its associated Service.»
Le rotte sono entrypoint per i servizi, caturano le richieste e le fanno processare al servizio associato.
Una rotta **non** esiste senza servizio (ne ha sempre al più uno) e un servizio **può** avere più rotte. S (1)<------(\*) R

## Upstream (https://docs.konghq.com/1.0.x/admin-api/# upstream-object)

«The upstream object represents a virtual hostname and can be used to loadbalance incoming requests over multiple services (targets)»
Come riporta la definizione rappresenta la definione di hst virtuale da usare nella definizone di un servizio. In pratica l'*upstream* può esistere senza servizio (anche se questo comporta che non viene usato) ma il servizio lo usa qualora dovesse gestire una chiamata **non** invocando direttamente un (micro) servizio esterno, **ma** un servizio "virtuale" (aka bilanciato).

## Target (https://docs.konghq.com/1.0.x/admin-api/# target-object)
«A target is an ip address/hostname with a port that identifies an instance of a backend service»
Stanno "dietro" agli upstream e ogni upstream può avere più target. si possono aggiungere dinamicamente, **non** possono essere cancellati al più si disabilitano dando loro peso 0.

## Consumer (https://docs.konghq.com/1.0.x/admin-api/# consumer-object)
«The Consumer object represents a consumer - or a user - of a Service»

## Certificate (https://docs.konghq.com/1.0.x/admin-api/# certificate-object)
«A certificate object represents a public certificate/private key pair for an SSL certificate»

## SNI (https://docs.konghq.com/1.0.x/admin-api/# sni-object)

«An SNI object represents a many-to-one mapping of hostnames to a certificate»
In pratica, al presentarsi di una data richiesta servibile alla porta TLS di Kong, è il legame che istruisco Kong su quale certificato usare per servire quella richiesta.


## Creazione del DB
Kong non salva, come invece fa httpd, su FS ma lo fa o su PG o su Cassandra. Questa cosa torna utile perché la clusterizzazione di Kong viene a costo zero (salvo remapping delle porte) indicando il db in comune.

Creazione del db:
    
```{.graph .center .bash}
    CREATE USER kong; CREATE DATABASE kong OWNER kong;

    alter user kong with encrypted password 'ubiest';

    grant all privileges on database kong to kong;
```

Popolamento e inizializzazione del db:

```{.graph .center .bash}
    docker run --rm \
        -e "KONG_DATABASE=postgres" \
        -e "KONG_PG_HOST=10.255.232.102" \
        -e "KONG_PG_PORT=5432" \
        -e "KONG_PG_USER=kong" \
        -e "KONG_PG_PASSWORD=ubiest" \
        -e "KONG_PG_DATABASE=kong" \
        -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
        -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
        kong kong migrations bootstrap
```

Creazione container kong al termine del quale abbiamo Kong funzionante:

```{.graph .center .bash}
    docker run -d --name kong \
        -e "KONG_DATABASE=postgres" \
        -e "KONG_PG_HOST=10.255.232.102" \
        -e "KONG_PG_PORT=5432" \
        -e "KONG_PG_USER=kong" \
        -e "KONG_PG_PASSWORD=ubiest" \
        -e "KONG_PG_DATABASE=kong" \
        -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
        -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \
        -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \
        -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \
        -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \
        -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" \
        -p 48000:8000 \
        -p 48443:8443 \
        -p 48001:8001 \
        -p 48444:8444 \
        kong
```pandoc kong.md --listing -H listing-setup.tex -o kong.pdf  --highlight-style=espresso

# konga

Comandi per la creazione di konga. Al primo accesso dopo aver impostato username e password va impostata graficamente l'istanza Konga cui appoggiarsi.

    docker pull pantsel/konga

    docker run -p 41337:1337  --name konga \
        -e "NODE_ENV=production" \
        -e "TOKEN_SECRET=t1z1@n0f3rr031s3tt3n@n1"  pantsel/kong

## Clustering
Kong è in grado di scalare orizzontalmente e la configurazione del cluster è implicita nel lanciare una nuova istanza condividendo con le precedenti il database PG (o Cassandra). Esistono delle configurazioni settabili tramite variabili d'ambiente di modo da fare tuning su politiche di caching e propagazione.

Una seconda istanza, testata all'interno del medesimo dockerd cambiandone le porte per ovvie ragioni, potrebbe, ad esempio, essere lanciata così:
    
```{.graph .center .bash}
    docker run -d --name kong2     \
        -e "KONG_DATABASE=postgres"     \
        -e "KONG_PG_HOST=10.255.232.102"     \
        -e "KONG_PG_PORT=5432"     \
        -e "KONG_PG_USER=kong"     \
        -e "KONG_PG_PASSWORD=ubiest"     \
        -e "KONG_PG_DATABASE=kong"     \
        -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database"     \
        -e "KONG_PROXY_ACCESS_LOG=/dev/stdout"     \
        -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout"     \
        -e "KONG_PROXY_ERROR_LOG=/dev/stderr"     \
        -e "KONG_ADMIN_ERROR_LOG=/dev/stderr"     \
        -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl"     -p 58000:8000     -p 58443:8443     -p 58001:8001     -p 58444:8444     kong
```

## Load balancing
il LB tra istanze diverse i Kong DEVE essere fatto da un bilanciatore posto a monte come avviene per Apache httpd


## Load Balancing internal

## # Prerequisiti per testare

Definire due servizi FAKE con netcat: questi simulano uno stupidissimo WEB server

in as01 lanciare:

```{.graph .center .bash}
    while true; do (echo -e 'HTTP/1.1 200 OK\r\n'; echo -e "\n\tMy website has date function AS01" ; echo -e "\t$(date)\n") | nc -lp 8080; done
```

in CS01 lanciare:
  
```{.graph .center .bash}
    while true; do (echo -e 'HTTP/1.1 200 OK\r\n'; echo -e "\n\tMy website has date function CS01" ; echo -e "\t$(date)\n") | nc -lp 8080; done
```

In questo modo abbiamo due server in ascolto sulla 8080 delle due macchine (10.255.232.101 e 10.255.232.102). Sotto verranno usate per deinire i target




```{.graph .center .bash}
    curl -X POST http://lb.mopar.vpn:48001/upstreams \
        --data "name=lb.fake.mopar.vpn"
```

Il "data" sopra specificato è come definire un virtual host che va usato nei comandi dopo . In ltre parole il "name" con cui si definisce l'upstream è lasciato liberamente definibile dall'utente PURCHE' po si usi uguale nella definizione del servizio (vedi dopo)

#  add two targets to the upstream

Queste istruzioni indicano come il virtualhost sopracitato deve invocare i servizi sottesti e con quali pesi


```{.graph .center .bash}
    curl -X POST http://lb.mopar.vpn:48001/upstreams/lb.fake.mopar.vpn/targets \
        --data "target=10.255.232.101:8080"
        --data "weight=100"
```
```{.graph .center .bash}
    curl -X POST http://lb.mopar.vpn:48001/upstreams/lb.fake.mopar.vpn/targets\
        --data "target=10.255.232.102:8080"
        --data "weight=50"
```
# create a Service targeting the Blue upstream
ATTENZIONE: qui l'host DEVE matchare il "name" specificato nella definizione dell'upstream

```{.graph .center .bash}
    curl -X POST http://lb.mopar.vpn:48001/services/ \
        --data "name=address-service" \
        --data "host=lb.fake.mopar.vpn" \
        --data "path=/"
```

# finally, add a Route as an entry-point into the Service

```{.graph .center .bash}
    curl -X POST http://lb.mopar.vpn:48001/services/address-service/routes/ \
        --data "hosts[]=ghesboro
```

Le rotte sono fondamentali specificando gli host a cui deve rispondere ho due alternative: 
  1) apache way: bastapresentartsi con quell'host come dominio
  2) ci si puà presentare con qualunque dominio  (anche l'ip) MA bisogna specificare nell'header "Host" il valore con cui si è definito l'host nella rotta. MOLTO UTILE quando si vuole testare una configurazione senza per forza aver definito gli host su DNS e/o /etc/hosts

Altra ipotesi da noi già utilizzata via apache  è che la discriminante sia il path 

```{.graph .center .bash}
    curl -i -X GET \
      --url http://lb.mopar.vpn:48000/ \
      --header 'Host: ghesboro'
```


LA discriminante è l'header se invece modifico una rotta elimnano l'header. E' nelle rotte che si agisce per capire COME gestire la chiamata. Oltre al routing via host header.

Abbiamo che la possibilità di fare un routing da path.

Considerazioni generali: 
non serve che il server ospitante kong abbia definiti lb.fake.mopar.vpn nei suo host/DNS

## Certificates

Si carica chiave e foglia  poi è l'SNI (tollroad.stage.mopar.vpn) che fa il matching tra richiesta entrante nella porta SSL (48443 negli esempi sopra) e certificato da usare. **ATTENZIONE** non sembra accettare "wildchars" ma c'è una pull request "validata" e accettata per implementarne il supporto per cui probabilmente verranno supportate.

## Rotte e RegEx
E' possibile creare rotte più specificative che, *probabilmente* (aka da verificarsi), verranno pioriticizzate in base alla loro lunghezza. Nell'incertezza nella loro definizone esiste un attributo priorità. Serve per esempio se, proxato tutto T2, vogliamo catturare solo certe richieste di alcuni path più specificativi, tipo public API, per poterci applicare dei plugin di rate limiting. 

Per i path params che ovviamente variano nel path, è possibile applicare, nella definizione della rotta, delle espressioni regolari


## Su alcuni parametri di Konga (e Kong)

- **Strip Path**: serve per torgliere il path specificato nella root nel momento in cui si proxa la richiesta. Se metto "/t2" nella root e dietro l'upstream ha context path "/t2" *senza* lo **Strip Path** mi ritorovo un "/t2t2" nella richiesta processata che ovviamente mi da un 404

- **Preserve host**: se la richiesta originaria è "stage.ubiest.com/t2" e **Preseve host** è "off" allora nel browser l'indirizzo verrà sostituito con l'indirizzo IP "interno" proxato

## Consumers e api-key (https://docs.konghq.com/1.0.x/getting-started/enabling-plugins/)

Serve per identificare un utente (aka consumer) con una apikey

1) creare un concumer via Konga e associare ad esso sotto la tab credentials una apikey

2) "proteggere" un servizio con apikey:

```
curl -i -X POST \                                                                                      
  --url http://10.255.232.103:48001/services/TollRoad/plugins/ \
  --data 'name=key-auth'
```

Così facendo sollo il campo "key_names" del servizio viene asseganto di default "apikey" che è la chiave passata come header o in query string sotto cui settare l'apikey del cunsumer. Se si fa via Konga occorre invece specificare esplicitamente almeno un valore per il "key_names"

## Metriche

Prometheus ... to be continued


## Censimento via API della app registrate in eureka per popolamento via script
 curl --url http://localhost:18761/eureka/apps | grep instanceId 
