Compare commits
5 Commits
v2024.6.27
...
v2024.6.27
Author | SHA1 | Date | |
---|---|---|---|
3565618335 | |||
64ca8fe1e4 | |||
d5669a4eb5 | |||
f3aa8b9be6 | |||
2de5e285a3 |
@ -12,13 +12,14 @@
|
|||||||
|
|
||||||
- [(FR) - Layers](./fr/references/layers/README.md)
|
- [(FR) - Layers](./fr/references/layers/README.md)
|
||||||
- [(FR) - Métriques](./fr/references/metrics.md)
|
- [(FR) - Métriques](./fr/references/metrics.md)
|
||||||
- [(FR) - Fichier de configuration](../misc/packaging/common/config.yml)
|
- [(FR) - Configuration](./fr/references/configuration.md)
|
||||||
- [(FR) - API d'administration](./fr/references/admin_api.md)
|
- [(FR) - API d'administration](./fr/references/admin_api.md)
|
||||||
|
|
||||||
## Tutoriels
|
## Tutoriels
|
||||||
|
|
||||||
### Utilisation
|
### Utilisation
|
||||||
|
|
||||||
|
- [(FR) - Le cas du "virtual hosting"](./fr/tutorials/virtual-hosting.md)
|
||||||
- [(FR) - Ajouter un layer de type "file d'attente"](./fr/tutorials/add-queue-layer.md)
|
- [(FR) - Ajouter un layer de type "file d'attente"](./fr/tutorials/add-queue-layer.md)
|
||||||
- [(FR) - Ajouter une authentification OpenID Connect](./fr/tutorials/add-oidc-authn-layer.md)
|
- [(FR) - Ajouter une authentification OpenID Connect](./fr/tutorials/add-oidc-authn-layer.md)
|
||||||
- [(FR) - Amorçage d'un serveur Bouncer via la configuration](./fr/tutorials/bootstrapping.md)
|
- [(FR) - Amorçage d'un serveur Bouncer via la configuration](./fr/tutorials/bootstrapping.md)
|
||||||
@ -28,3 +29,4 @@
|
|||||||
|
|
||||||
- [(FR) - Démarrer avec les sources](./fr/tutorials/getting-started-with-sources.md)
|
- [(FR) - Démarrer avec les sources](./fr/tutorials/getting-started-with-sources.md)
|
||||||
- [(FR) - Créer son propre layer](./fr/tutorials/create-custom-layer.md)
|
- [(FR) - Créer son propre layer](./fr/tutorials/create-custom-layer.md)
|
||||||
|
- [(FR) - Étudier les performances de Bouncer](./fr/tutorials/profiling.md)
|
||||||
|
34
doc/fr/references/configuration.md
Normal file
34
doc/fr/references/configuration.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Configuration
|
||||||
|
|
||||||
|
## Référence
|
||||||
|
|
||||||
|
Vous trouverez ici un fichier de configuration de référence, complet et commenté:
|
||||||
|
|
||||||
|
[`misc/packaging/common/config.yml`](../../../misc/packaging/common/config.yml)
|
||||||
|
|
||||||
|
## Interpolation de variables
|
||||||
|
|
||||||
|
Il est possible d'utiliser de l'interpolation de variables d'environnement dans le fichier de configuration via la syntaxe `${var}`.
|
||||||
|
|
||||||
|
Les fonctions d'interpolation suivantes sont également disponibles:
|
||||||
|
|
||||||
|
- `${var^}`
|
||||||
|
- `${var^^}`
|
||||||
|
- `${var,}`
|
||||||
|
- `${var,,}`
|
||||||
|
- `${var:position}`
|
||||||
|
- `${var:position:length}`
|
||||||
|
- `${var#substring}`
|
||||||
|
- `${var##substring}`
|
||||||
|
- `${var%substring}`
|
||||||
|
- `${var%%substring}`
|
||||||
|
- `${var/substring/replacement}`
|
||||||
|
- `${var//substring/replacement}`
|
||||||
|
- `${var/#substring/replacement}`
|
||||||
|
- `${var/%substring/replacement}`
|
||||||
|
- `${#var}`
|
||||||
|
- `${var=default}`
|
||||||
|
- `${var:=default}`
|
||||||
|
- `${var:-default}`
|
||||||
|
|
||||||
|
_Voir le package [`github.com/drone/envsubst`](https://pkg.go.dev/github.com/drone/envsubst) pour plus de détails._
|
@ -1,4 +1,4 @@
|
|||||||
# Analyser les performances de Bouncer
|
# Étudier les performances de Bouncer
|
||||||
|
|
||||||
1. Lancer un benchmark du proxy
|
1. Lancer un benchmark du proxy
|
||||||
|
|
||||||
|
129
doc/fr/tutorials/virtual-hosting.md
Normal file
129
doc/fr/tutorials/virtual-hosting.md
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
# Le cas du "virtual hosting"
|
||||||
|
|
||||||
|
De nombreux serveurs HTTP utilisent le mécanisme du ["virtual hosting"](https://en.wikipedia.org/wiki/Virtual_hosting) afin d'héberger plusieurs sites/applications différentes sur un même serveur, se basant alors sur l'entête HTTP `Host` pour effectuer le routage.
|
||||||
|
|
||||||
|
## Exemple
|
||||||
|
|
||||||
|
Pour exemple, avec le site [example.net](https://example.net) il est facile de tester ce type de comportement. Ainsi, en exécutant une requête HTTP avec `curl`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -I https://example.net
|
||||||
|
```
|
||||||
|
|
||||||
|
On obtient le résultat suivant:
|
||||||
|
|
||||||
|
```
|
||||||
|
HTTP/2 200
|
||||||
|
accept-ranges: bytes
|
||||||
|
age: 568237
|
||||||
|
cache-control: max-age=604800
|
||||||
|
content-type: text/html; charset=UTF-8
|
||||||
|
date: Thu, 27 Jun 2024 08:32:46 GMT
|
||||||
|
etag: "3147526947"
|
||||||
|
expires: Thu, 04 Jul 2024 08:32:46 GMT
|
||||||
|
last-modified: Thu, 17 Oct 2019 07:18:26 GMT
|
||||||
|
server: ECAcc (bsb/2789)
|
||||||
|
x-cache: HIT
|
||||||
|
content-length: 1256
|
||||||
|
```
|
||||||
|
|
||||||
|
Ce résultat indique que le serveur a correctement orienté notre requête (code HTTP `200`) et qu'il nous a renvoyé la réponse attendue.
|
||||||
|
|
||||||
|
Si maintenant on modifie l'entête `Host` de notre requête pour la remplacer par une valeur arbitraire:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -I -H 'Host: localhost:8080' https://example.net
|
||||||
|
```
|
||||||
|
|
||||||
|
On obtient alors le résultat:
|
||||||
|
|
||||||
|
```
|
||||||
|
HTTP/2 404
|
||||||
|
content-type: text/html
|
||||||
|
date: Thu, 27 Jun 2024 08:38:04 GMT
|
||||||
|
server: ECAcc (bsb/2789)
|
||||||
|
content-length: 345
|
||||||
|
```
|
||||||
|
|
||||||
|
Le serveur nous répond avec un code HTTP `404`, indiquant qu'il n'a pas trouvé la page demandée.
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
> Le code HTTP retourné par le serveur peut varier en fonction des implémentations. Parfois la requête sera orientée vers la page par défaut, parfois vous recevrez un code d'erreur HTTP comme `404`, `421`, etc.
|
||||||
|
|
||||||
|
## Avec Bouncer
|
||||||
|
|
||||||
|
Ce mécanisme peut parfois poser problème avec Bouncer car par défaut celui ci n'effectue pas de réécriture de l'entête `Host`. Pour exemple:
|
||||||
|
|
||||||
|
1. Créez puis activez un nouveau proxy pointant vers https://example.net
|
||||||
|
|
||||||
|
```shell
|
||||||
|
bouncer admin proxy create --proxy-name example --proxy-to https://example.net
|
||||||
|
bouncer admin proxy update --proxy-name example --proxy-enabled=true
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Avec `curl`, faites une requête sur votre nouveau proxy:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -I http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
La réponse devrait ressembler à:
|
||||||
|
|
||||||
|
```
|
||||||
|
HTTP/1.1 404 Not Found
|
||||||
|
Content-Length: 345
|
||||||
|
Content-Type: text/html
|
||||||
|
Date: Thu, 27 Jun 2024 08:49:05 GMT
|
||||||
|
Server: ECAcc (bsb/2789)
|
||||||
|
```
|
||||||
|
|
||||||
|
On retrouve bien notre code HTTP `404` tel que vu plus haut. En effet, vu que l'on accède au proxy Bouncer avec `http://localhost:8080` alors le serveur distant recevra l'entête `Host: localhost:8080`.
|
||||||
|
|
||||||
|
### Comment corriger la situation ?
|
||||||
|
|
||||||
|
Le layer [`rewriter`](../references/layers/rewriter.md) a été implémenté notamment pour répondre à ce type de cas. Voyons comment l'utiliser:
|
||||||
|
|
||||||
|
1. Créez puis activez un nouveau layer pour votre proxy `example`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Création du layer
|
||||||
|
bouncer admin layer create --proxy-name example --layer-name host-rewrite --layer-type rewriter
|
||||||
|
|
||||||
|
# Mise à jour et activation du layer
|
||||||
|
bouncer admin layer update \
|
||||||
|
--proxy-name example \
|
||||||
|
--layer-name host-rewrite \
|
||||||
|
--layer-options '{ "rules": { "request": ["set_host(\"example.net\")"] } }' \
|
||||||
|
--layer-enabled=true
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Les règles**
|
||||||
|
>
|
||||||
|
> Le layer `rewriter` permet la modification des requêtes/réponses via un moteur de règles.
|
||||||
|
>
|
||||||
|
> [Voir la page du layer pour plus d'informations](../references/layers/rewriter.md) sur la syntaxe ainsi que sur l'API à disposition des règles.
|
||||||
|
|
||||||
|
2. Testez maintenant à nouveau un appel vers votre proxy:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -I http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
La réponse devrait ressembler à:
|
||||||
|
|
||||||
|
```
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Accept-Ranges: bytes
|
||||||
|
Age: 569980
|
||||||
|
Cache-Control: max-age=604800
|
||||||
|
Content-Length: 1256
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Date: Thu, 27 Jun 2024 09:01:49 GMT
|
||||||
|
Etag: "3147526947"
|
||||||
|
Expires: Thu, 04 Jul 2024 09:01:49 GMT
|
||||||
|
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
|
||||||
|
Server: ECAcc (bsb/2789)
|
||||||
|
X-Cache: HIT
|
||||||
|
```
|
||||||
|
|
||||||
|
Cette fois ci, le serveur distant a bien identifié la cible de notre requête.
|
@ -2,7 +2,6 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -11,9 +10,6 @@ import (
|
|||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// var reVar = regexp.MustCompile(`^\${(\w+)}$`)
|
|
||||||
var reVar = regexp.MustCompile(`\${(.*?)}`)
|
|
||||||
|
|
||||||
type InterpolatedString string
|
type InterpolatedString string
|
||||||
|
|
||||||
func (is *InterpolatedString) UnmarshalYAML(value *yaml.Node) error {
|
func (is *InterpolatedString) UnmarshalYAML(value *yaml.Node) error {
|
||||||
@ -23,12 +19,13 @@ func (is *InterpolatedString) UnmarshalYAML(value *yaml.Node) error {
|
|||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
|
str, err := envsubst.EvalEnv(str)
|
||||||
*is = InterpolatedString(os.Getenv(match[1]))
|
if err != nil {
|
||||||
} else {
|
return errors.WithStack(err)
|
||||||
*is = InterpolatedString(str)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*is = InterpolatedString(str)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,8 +38,9 @@ func (ii *InterpolatedInt) UnmarshalYAML(value *yaml.Node) error {
|
|||||||
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
|
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
|
str, err := envsubst.EvalEnv(str)
|
||||||
str = os.Getenv(match[1])
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
intVal, err := strconv.ParseInt(str, 10, 32)
|
intVal, err := strconv.ParseInt(str, 10, 32)
|
||||||
@ -64,11 +62,12 @@ func (ifl *InterpolatedFloat) UnmarshalYAML(value *yaml.Node) error {
|
|||||||
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
|
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
|
str, err := envsubst.EvalEnv(str)
|
||||||
str = os.Getenv(match[1])
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
floatVal, err := strconv.ParseFloat(str, 10)
|
floatVal, err := strconv.ParseFloat(str, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not parse float '%v', line '%d'", str, value.Line)
|
return errors.Wrapf(err, "could not parse float '%v', line '%d'", str, value.Line)
|
||||||
}
|
}
|
||||||
@ -87,8 +86,9 @@ func (ib *InterpolatedBool) UnmarshalYAML(value *yaml.Node) error {
|
|||||||
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
|
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
|
str, err := envsubst.EvalEnv(str)
|
||||||
str = os.Getenv(match[1])
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
boolVal, err := strconv.ParseBool(str)
|
boolVal, err := strconv.ParseBool(str)
|
||||||
@ -165,22 +165,15 @@ type InterpolatedStringSlice []string
|
|||||||
|
|
||||||
func (iss *InterpolatedStringSlice) UnmarshalYAML(value *yaml.Node) error {
|
func (iss *InterpolatedStringSlice) UnmarshalYAML(value *yaml.Node) error {
|
||||||
var data []string
|
var data []string
|
||||||
var evErr error
|
|
||||||
|
|
||||||
if err := value.Decode(&data); err != nil {
|
if err := value.Decode(&data); err != nil {
|
||||||
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into map", value.Value, value.Line)
|
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into map", value.Value, value.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
for index, value := range data {
|
for index, value := range data {
|
||||||
//match := reVar.FindStringSubmatch(value)
|
value, err := envsubst.EvalEnv(value)
|
||||||
re := regexp.MustCompile(`\${(.*?)}`)
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
res := re.FindAllStringSubmatch(value, 10)
|
|
||||||
if len(res) > 0 {
|
|
||||||
value, evErr = envsubst.EvalEnv(value)
|
|
||||||
if evErr != nil {
|
|
||||||
return evErr
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data[index] = value
|
data[index] = value
|
||||||
@ -200,8 +193,9 @@ func (id *InterpolatedDuration) UnmarshalYAML(value *yaml.Node) error {
|
|||||||
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
|
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
|
str, err := envsubst.EvalEnv(str)
|
||||||
str = os.Getenv(match[1])
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
duration, err := time.ParseDuration(str)
|
duration, err := time.ParseDuration(str)
|
||||||
|
Reference in New Issue
Block a user