Skip to content

Commit

Permalink
MINOR: add client-strict-sni annotation
Browse files Browse the repository at this point in the history
When enbaled HAProxy will only accept TLS client connections where
the provided SNI matchs an existing certificate. Otherwise the default
certificate will be provided when the provided SNI does not match.
  • Loading branch information
Mo3m3n committed Mar 2, 2022
1 parent 885d61c commit 4fe08ee
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 15 deletions.
26 changes: 15 additions & 11 deletions controller/handler/https.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,15 @@ import (
)

type HTTPS struct {
Enabled bool
IPv4 bool
IPv6 bool
Port int64
AddrIPv4 string
AddrIPv6 string
CertDir string
Alpn string
Enabled bool
IPv4 bool
IPv6 bool
strictSNI bool
Port int64
AddrIPv4 string
AddrIPv6 string
CertDir string
alpn string
}

func (h HTTPS) bindList(passhthrough bool) (binds []models.Bind) {
Expand Down Expand Up @@ -147,12 +148,15 @@ func (h HTTPS) Update(k store.K8s, cfg *config.ControllerCfg, api api.HAProxyCli
}

// Fetch tls-alpn value for when SSL offloading is enabled
h.Alpn = annotations.String("tls-alpn", k.ConfigMaps.Main.Annotations)
h.alpn = annotations.String("tls-alpn", k.ConfigMaps.Main.Annotations)

h.strictSNI, err = annotations.Bool("client-strict-sni", k.ConfigMaps.Main.Annotations)
logger.Error(err)

// ssl-offload
if cfg.Certificates.FrontendCertsEnabled() {
if !cfg.HTTPS {
logger.Panic(api.FrontendEnableSSLOffload(cfg.FrontHTTPS, h.CertDir, h.Alpn))
logger.Panic(api.FrontendEnableSSLOffload(cfg.FrontHTTPS, h.CertDir, h.alpn, h.strictSNI))
cfg.HTTPS = true
reload = true
logger.Debug("SSLOffload enabeld, reload required")
Expand Down Expand Up @@ -253,7 +257,7 @@ func (h HTTPS) toggleSSLPassthrough(passthrough bool, cfg *config.ControllerCfg,
}
}
if cfg.HTTPS {
logger.Panic(api.FrontendEnableSSLOffload(cfg.FrontHTTPS, h.CertDir, h.Alpn))
logger.Panic(api.FrontendEnableSSLOffload(cfg.FrontHTTPS, h.CertDir, h.alpn, h.strictSNI))
}
return nil
}
Expand Down
4 changes: 2 additions & 2 deletions controller/handler/tcp-services.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func (t TCPServices) createTCPFrontend(api api.HAProxyClient, frontendName, bind
}))
}
if sslOffload {
errors.Add(api.FrontendEnableSSLOffload(frontend.Name, t.CertDir, ""))
errors.Add(api.FrontendEnableSSLOffload(frontend.Name, t.CertDir, "", false))
}
if errors.Result() != nil {
err = fmt.Errorf("error configuring tcp frontend: %w", err)
Expand All @@ -159,7 +159,7 @@ func (t TCPServices) updateTCPFrontend(k store.K8s, cfg *config.ControllerCfg, a
return
}
if !binds[0].Ssl && p.sslOffload {
err = api.FrontendEnableSSLOffload(frontend.Name, t.CertDir, "")
err = api.FrontendEnableSSLOffload(frontend.Name, t.CertDir, "", false)
if err != nil {
err = fmt.Errorf("failed to enable SSL offload: %w", err)
return
Expand Down
2 changes: 1 addition & 1 deletion controller/haproxy/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type HAProxyClient interface {
FrontendsGet() (models.Frontends, error)
FrontendGet(frontendName string) (models.Frontend, error)
FrontendEdit(frontend models.Frontend) error
FrontendEnableSSLOffload(frontendName string, certDir string, alpn string) (err error)
FrontendEnableSSLOffload(frontendName string, certDir string, alpn string, strictSNI bool) (err error)
FrontendDisableSSLOffload(frontendName string) (err error)
FrontendBindsGet(frontend string) (models.Binds, error)
FrontendBindCreate(frontend string, bind models.Bind) error
Expand Down
4 changes: 3 additions & 1 deletion controller/haproxy/api/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (c *clientNative) FrontendEdit(frontend models.Frontend) error {
return c.nativeAPI.Configuration.EditFrontend(frontend.Name, &frontend, c.activeTransaction, 0)
}

func (c *clientNative) FrontendEnableSSLOffload(frontendName string, certDir string, alpn string) (err error) {
func (c *clientNative) FrontendEnableSSLOffload(frontendName string, certDir string, alpn string, strictSNI bool) (err error) {
binds, err := c.FrontendBindsGet(frontendName)
if err != nil {
return err
Expand All @@ -61,6 +61,7 @@ func (c *clientNative) FrontendEnableSSLOffload(frontendName string, certDir str
bind.SslCertificate = certDir
if alpn != "" {
bind.Alpn = alpn
bind.StrictSni = strictSNI
}
err = c.FrontendBindEdit(frontendName, *bind)
}
Expand All @@ -81,6 +82,7 @@ func (c *clientNative) FrontendDisableSSLOffload(frontendName string) (err error
bind.Verify = ""
bind.SslCertificate = ""
bind.Alpn = ""
bind.StrictSni = false
err = c.FrontendBindEdit(frontendName, *bind)
}
if err != nil {
Expand Down
19 changes: 19 additions & 0 deletions documentation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ This is autogenerated from [doc.yaml](doc.yaml). Description can be found in [ge
| [clean-certs](#clean-certs) | [bool](#bool) | "true" | |:large_blue_circle:|:white_circle:|:white_circle:|
| [client-ca](#authentication) | string | | ssl-offloading |:large_blue_circle:|:white_circle:|:white_circle:|
| [client-crt-optional](#authentication) | [bool](#bool) | "false" | client-ca |:large_blue_circle:|:white_circle:|:white_circle:|
| [client-strict-sni](#ssl-offloading) | [bool](#bool) | "false" | client-ca |:large_blue_circle:|:white_circle:|:white_circle:|
| [cors-enable](#CORS) | [bool](#bool) | "false" | |:large_blue_circle:|:large_blue_circle:|:white_circle:|
| [cors-allow-origin](#CORS) | string | "*" | cors-enable |:large_blue_circle:|:large_blue_circle:|:white_circle:|
| [cors-allow-methods](#CORS) | string | "*" | cors-enable |:large_blue_circle:|:large_blue_circle:|:white_circle:|
Expand Down Expand Up @@ -1513,6 +1514,24 @@ src-ip-header: "True-Client-IP"
- Certificates can be defined in Ingress object: `spec.tls[].secretName`


##### `client-strict-sni`

If enabled, HAProxy will only accept TLS client connections where the provided SNI matchs an existing certificate.
If disabled HAProxy will service the default certificate when the provided SNI does not match.

Available on: `configmap`

Possible values:

- true
- false `default`

Example:

```yaml
client-strict-sni: true
```

##### `ssl-certificate`

Sets the name of the Kubernetes secret that contains both the TLS key and certificate.
Expand Down
16 changes: 16 additions & 0 deletions documentation/doc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,22 @@ annotations:
version_min: "1.6"
example:
- "client-crt-optional: true"
- title: client-strict-sni
type: bool
group: ssl-offloading
dependencies: client-ca
default: "false"
description:
- If enabled, HAProxy will only accept TLS client connections where the provided SNI matchs an existing certificate.
- If disabled HAProxy will service the default certificate when the provided SNI does not match.
values:
- "true"
- "false"
applies_to:
- configmap
version_min: "1.7"
example:
- "client-strict-sni: true"
- title: cors-enable
type: bool
group: CORS
Expand Down

0 comments on commit 4fe08ee

Please sign in to comment.