Skip to content

Commit

Permalink
Merge pull request #755 from jcmoraisjr/jm-config-proxy
Browse files Browse the repository at this point in the history
Add custom-proxy configuration
  • Loading branch information
jcmoraisjr authored Mar 18, 2021
2 parents 03c76e9 + 6fd5b98 commit 057c2e5
Show file tree
Hide file tree
Showing 7 changed files with 248 additions and 12 deletions.
25 changes: 17 additions & 8 deletions docs/content/en/docs/configuration/keys.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ The table below describes all supported configuration keys.
| [`config-defaults`](#configuration-snippet) | multiline HAProxy config for the defaults section | Global | |
| [`config-frontend`](#configuration-snippet) | multiline HAProxy frontend config | Global | |
| [`config-global`](#configuration-snippet) | multiline HAProxy global config | Global | |
| [`config-proxy`](#configuration-snippet) | multiline HAProxy custom proxy config | Global | |
| [`config-sections`](#configuration-snippet) | multiline HAProxy section declarations | Global | |
| [`cookie-key`](#affinity) | secret key | Global | `Ingress` |
| [`cors-allow-credentials`](#cors) | [true\|false] | Path | |
Expand Down Expand Up @@ -1016,11 +1017,19 @@ See also:
| `config-defaults` | `Global` | | v0.8 |
| `config-frontend` | `Global` | | |
| `config-global` | `Global` | | |
| `config-proxy` | `Global` | | v0.13 |
| `config-sections` | `Global` | | v0.13 |

Add HAProxy configuration snippet to the configuration file. Use multiline content
to add more than one line of configuration.

* `config-backend`: Adds a configuration snippet to a HAProxy backend section.
* `config-defaults`: Adds a configuration snippet to the end of the HAProxy defaults section.
* `config-frontend`: Adds a configuration snippet to the HTTP and HTTPS frontend sections.
* `config-global`: Adds a configuration snippet to the end of the HAProxy global section.
* `config-proxy`: Adds a configuration snippet to any HAProxy proxy - listen, frontend or backend. It accepts a multi section configuration, where the name of the section is the name of a HAProxy proxy without the listen/frontend/backend prefix. A section whose proxy is not found is ignored. The content of each section should be indented, the first line without indentation is the start of a new section which will configure another proxy.
* `config-sections`: Allows to declare new HAProxy sections. The configuration is used verbatim, without any indentation or validation.

Examples - ConfigMap:

```yaml
Expand All @@ -1033,6 +1042,14 @@ Examples - ConfigMap:
option redispatch
```

```yaml
config-proxy: |
_tcp_default_postgresql_5432
tcp-request content reject if !{ src 10.0.0.0/8 }
_front__tls
tcp-request content reject if !{ src 10.0.0.0/8 } { req.ssl_sni -m reg ^intra\..* }
```

```yaml
config-sections: |
cache icons
Expand Down Expand Up @@ -1064,14 +1081,6 @@ Annotation:
http-response cache-store icons if { var(txn.path) -m end .ico }
```

The following keys add a configuration snippet to the ...:

* `config-backend`: ... HAProxy backend section.
* `config-global`: ... end of the HAProxy global section.
* `config-defaults`: ... end of the HAProxy defaults section.
* `config-frontend`: ... HAProxy frontend sections.
* `config-sections`: ... HAProxy new section declarations.

---

## Connection
Expand Down
17 changes: 17 additions & 0 deletions pkg/converters/ingress/annotations/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,4 +345,21 @@ func (c *updater) buildGlobalCustomConfig(d *globalData) {
d.global.CustomDefaults = utils.LineToSlice(d.mapper.Get(ingtypes.GlobalConfigDefaults).Value)
d.global.CustomFrontend = utils.LineToSlice(d.mapper.Get(ingtypes.GlobalConfigFrontend).Value)
d.global.CustomSections = utils.LineToSlice(d.mapper.Get(ingtypes.GlobalConfigSections).Value)
proxy := map[string][]string{}
var curSection string
for _, line := range utils.LineToSlice(d.mapper.Get(ingtypes.GlobalConfigProxy).Value) {
if line == "" {
continue
}
if line[0] != ' ' && line[0] != '\t' {
curSection = line
continue
}
proxy[curSection] = append(proxy[curSection], strings.TrimSpace(line))
}
if lines, hasEmpty := proxy[""]; hasEmpty {
c.logger.Warn("non scoped %d line(s) in the config-proxy configuration were ignored", len(lines))
delete(proxy, "")
}
d.global.CustomProxy = proxy
}
58 changes: 58 additions & 0 deletions pkg/converters/ingress/annotations/global_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,64 @@ func TestBind(t *testing.T) {
}
}

func TestCustomConfigProxy(t *testing.T) {
testCases := []struct {
config string
expected map[string][]string
logging string
}{
// 0
{},
// 1
{
config: `
proxy_1
acl test`,
expected: map[string][]string{
"proxy_1": {"acl test"},
},
},
// 2
{
config: `
backend_1
acl ok always_true
http-request deny if !ok
backend_2
## two spaces
## four spaces
## two tabs`,
expected: map[string][]string{
"backend_1": {"acl ok always_true", "http-request deny if !ok"},
"backend_2": {"## two spaces", "## four spaces", "## two tabs"},
},
},
// 3
{
config: `
## trailing line 1
proxy_1
acl ok always_true
`,
expected: map[string][]string{
"proxy_1": {"acl ok always_true"},
},
logging: `WARN non scoped 1 line(s) in the config-proxy configuration were ignored`,
},
}
for i, test := range testCases {
c := setup(t)
d := c.createGlobalData(map[string]string{ingtypes.GlobalConfigProxy: test.config})
c.createUpdater().buildGlobalCustomConfig(d)
if test.expected == nil {
test.expected = map[string][]string{}
}
c.compareObjects("custom config", i, d.global.CustomProxy, test.expected)
c.logger.CompareLogging(test.logging)
c.teardown()
}
}

func TestModSecurity(t *testing.T) {
testCases := []struct {
endpoints string
Expand Down
1 change: 1 addition & 0 deletions pkg/converters/ingress/types/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
GlobalConfigDefaults = "config-defaults"
GlobalConfigFrontend = "config-frontend"
GlobalConfigGlobal = "config-global"
GlobalConfigProxy = "config-proxy"
GlobalConfigSections = "config-sections"
GlobalCookieKey = "cookie-key"
GlobalCPUMap = "cpu-map"
Expand Down
106 changes: 106 additions & 0 deletions pkg/haproxy/instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2309,6 +2309,112 @@ backend d1_app_8080
c.logger.CompareLogging(defaultLogging)
}

func TestInstanceCustomProxy(t *testing.T) {
c := setup(t)
defer c.teardown()

var h *hatypes.Host
var b *hatypes.Backend

b = c.config.Backends().AcquireBackend("d1", "app", "8080")
b.Endpoints = []*hatypes.Endpoint{endpointS1}
h = c.config.Hosts().AcquireHost("d1.local")
h.AddPath(b, "/", hatypes.MatchBegin)
h.SetSSLPassthrough(true)

tcp := c.config.tcpbackends.Acquire("default_pgsql", 5432)
tcp.AddEndpoint("172.17.0.21", 5432)

c.config.Global().CustomProxy = map[string][]string{
"missing": {"## comment"},
"_tcp_default_pgsql_5432": {"## custom for _tcp_default_pgsql_5432"},
"d1_app_8080": {"## custom for d1_app_8080"},
"_redirect_https": {"## custom for _redirect_https"},
"_error404": {"## custom for _error404", "## line 2"},
"_front__tls": {"## custom for _front__tls"},
"_front_http": {"## custom for _front_http"},
"_front_https": {"## custom for _front_https"},
"stats": {"## custom for stats"},
"healthz": {"## custom for healthz"},
}

c.Update()
c.checkConfig(`
<<global>>
<<defaults>>
listen _tcp_default_pgsql_5432
bind :5432
mode tcp
## custom for _tcp_default_pgsql_5432
server srv001 172.17.0.21:5432
backend d1_app_8080
mode http
## custom for d1_app_8080
server s1 172.17.0.11:8080 weight 100
backend _redirect_https
mode http
## custom for _redirect_https
http-request redirect scheme https
backend _error404
mode http
## custom for _error404
## line 2
http-request use-service lua.send-404
listen _front__tls
mode tcp
bind :443
tcp-request inspect-delay 5s
tcp-request content set-var(req.sslpassback) req.ssl_sni,lower,map_str(/etc/haproxy/maps/_front_sslpassthrough__exact.map)
## custom for _front__tls
tcp-request content accept if { req.ssl_hello_type 1 }
use_backend %[var(req.sslpassback)] if { var(req.sslpassback) -m found }
server _default_server_https_socket unix@/var/run/haproxy/_https_socket.sock send-proxy-v2
frontend _front_http
mode http
bind :80
http-request set-var(req.path) path
http-request set-var(req.host) hdr(host),field(1,:),lower
http-request set-var(req.base) var(req.host),concat(,req.path)
http-request set-header X-Forwarded-Proto http
http-request del-header X-SSL-Client-CN
http-request del-header X-SSL-Client-DN
http-request del-header X-SSL-Client-SHA1
http-request del-header X-SSL-Client-Cert
http-request set-var(req.backend) var(req.base),lower,map_beg(/etc/haproxy/maps/_front_http_host__begin.map)
## custom for _front_http
use_backend %[var(req.backend)] if { var(req.backend) -m found }
default_backend _error404
frontend _front_https
mode http
bind unix@/var/run/haproxy/_https_socket.sock accept-proxy ssl alpn h2,http/1.1 crt-list /etc/haproxy/maps/_front_bind_crt.list ca-ignore-err all crt-ignore-err all
http-request set-header X-Forwarded-Proto https
http-request del-header X-SSL-Client-CN
http-request del-header X-SSL-Client-DN
http-request del-header X-SSL-Client-SHA1
http-request del-header X-SSL-Client-Cert
## custom for _front_https
use_backend %[var(req.hostbackend)] if { var(req.hostbackend) -m found }
default_backend _error404
listen stats
mode http
bind :1936
stats enable
stats uri /
no log
option httpclose
stats show-legends
## custom for stats
frontend healthz
mode http
bind :10253
monitor-uri /healthz
http-request use-service lua.send-404
no log
## custom for healthz
`)
c.logger.CompareLogging(defaultLogging)
}

func TestInstanceSSLPassthrough(t *testing.T) {
c := setup(t)
defer c.teardown()
Expand Down
1 change: 1 addition & 0 deletions pkg/haproxy/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type Global struct {
CustomConfig []string
CustomDefaults []string
CustomFrontend []string
CustomProxy map[string][]string
CustomSections []string
}

Expand Down
Loading

0 comments on commit 057c2e5

Please sign in to comment.