Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions deploy/haproxy-ingress.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ metadata:
namespace: haproxy-controller
data:
ssl-redirect-port: "443"
generate-certificates: "true"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this value? Shouldn't it be as false?


---
apiVersion: apps/v1
Expand Down
48 changes: 48 additions & 0 deletions documentation/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ This is autogenerated from [doc.yaml](doc.yaml). Description can be found in [ge
| [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:|
| [generate-certificates](#ssl-offloading) | [bool](#bool) | "false" | |:large_blue_circle:|:white_circle:|:white_circle:|
| [ca-sign-file](#ssl-offloading) | string | | generate-certificates |: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 @@ -1698,6 +1700,52 @@ Example:
client-strict-sni: true
```

##### `generate-certificates`

Enables automatic certificate generation on the HTTPS frontend bind line using HAProxy's generate-certificates feature.
This allows HAProxy to automatically generate certificates for incoming TLS connections.

Available on: `configmap`

:information_source: This requires HAProxy to be configured with a ca-sign-file for certificate generation to work.

:information_source: The generate-certificates option is added to the bind line in the HTTPS frontend when SSL offload is enabled.

Possible values:

- true
- false `default`

Example:

```yaml
generate-certificates: true
```

##### `ca-sign-file`

Specifies the Kubernetes secret containing the CA certificate file used to sign automatically generated certificates.
This annotation works in conjunction with generate-certificates to provide the signing CA for certificate generation.
The secret should contain the CA certificate in PEM format.

Available on: `configmap`

:information_source: This is only used when generate-certificates is enabled.

:information_source: The secret format should be namespace/secret-name.

:information_source: HAProxy will use this CA to sign certificates generated for incoming TLS connections.

Possible values:

- Name of Kubernetes secret in format namespace/secret-name

Example:

```yaml
ca-sign-file: "default/ca-signing-cert"
```

##### `ssl-certificate`

Sets the name of the Kubernetes secret that contains both the TLS key and certificate.
Expand Down
39 changes: 39 additions & 0 deletions documentation/doc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,45 @@ annotations:
version_min: "1.8"
example:
- "client-strict-sni: true"
- title: generate-certificates
type: bool
group: ssl-offloading
dependencies: ""
default: "false"
description:
- Enables automatic certificate generation on the HTTPS frontend bind line using HAProxy's generate-certificates feature.
- This allows HAProxy to automatically generate certificates for incoming TLS connections.
tip:
- This requires HAProxy to be configured with a ca-sign-file for certificate generation to work.
- The generate-certificates option is added to the bind line in the HTTPS frontend when SSL offload is enabled.
values:
- "true"
- "false"
applies_to:
- configmap
version_min: "1.11"
example:
- "generate-certificates: true"
- title: ca-sign-file
type: string
group: ssl-offloading
dependencies: generate-certificates
default: ""
description:
- Specifies the Kubernetes kubernetes.io/tls type secret containing the CA certificate file used to sign automatically generated certificates.
- This annotation works in conjunction with generate-certificates to provide the signing CA for certificate generation.
- The secret should contain the CA certificate in PEM format.
tip:
- This is only used when generate-certificates is enabled.
- The secret format should be namespace/secret-name or just secret-name (uses controller namespace).
- HAProxy will use this CA to sign certificates generated for incoming TLS connections.
values:
- Name of Kubernetes secret in format namespace/secret-name
applies_to:
- configmap
version_min: "1.11"
example:
- 'ca-sign-file: "default/ca-signing-cert"'
- title: cors-enable
type: bool
group: CORS
Expand Down
2 changes: 2 additions & 0 deletions pkg/annotations/common/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ var DefaultValues = map[string]string{
"client-crt-optional": "false",
"tls-alpn": "h2,http/1.1",
"quic-alt-svc-max-age": "60",
"generate-certificates": "false",
"ca-sign-file": "",
}

// Returns the first annotation value in the set of maps of annotations along with the indice of which map in argument provided the value.
Expand Down
50 changes: 39 additions & 11 deletions pkg/handler/https.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,17 @@ import (
)

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

//nolint:golint, stylecheck
Expand Down Expand Up @@ -170,11 +172,37 @@ func (handler *HTTPS) Update(k store.K8s, h haproxy.HAProxy, a annotations.Annot
handler.strictSNI, err = annotations.Bool("client-strict-sni", k.ConfigMaps.Main.Annotations)
logger.Error(err)

handler.generateCertificates, err = annotations.Bool("generate-certificates", k.ConfigMaps.Main.Annotations)
logger.Error(err)

// Handle ca-sign-file secret for certificate generation
handler.caSignFile = ""
if handler.generateCertificates {
var notFound store.ErrNotFound
secret, annErr := annotations.Secret("ca-sign-file", "", k, k.ConfigMaps.Main.Annotations)
if annErr != nil {
if errors.Is(annErr, notFound) {
logger.Debugf("ca-sign-file not configured: %s", annErr)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be a warning

} else {
err = fmt.Errorf("ca-sign-file: %w", annErr)
return err
}
}
if secret != nil {
caFile, certErr := h.Certificates.AddSecret(secret, certs.FT_CERT)
if certErr != nil {
err = fmt.Errorf("ca-sign-file: %w", certErr)
return err
}
handler.caSignFile = caFile
}
}

// ssl-offload
sslOffloadEnabled := h.FrontendSSLOffloadEnabled(h.FrontHTTPS)
if h.FrontCertsInUse() {
if !sslOffloadEnabled {
logger.Panic(h.FrontendEnableSSLOffload(h.FrontHTTPS, handler.CertDir, handler.alpn, handler.strictSNI))
logger.Panic(h.FrontendEnableSSLOffload(h.FrontHTTPS, handler.CertDir, handler.alpn, handler.strictSNI, handler.generateCertificates, handler.caSignFile))
instance.Reload("SSL offload enabled")
}
err := handler.handleClientTLSAuth(k, h)
Expand Down Expand Up @@ -268,7 +296,7 @@ func (handler *HTTPS) toggleSSLPassthrough(passthrough bool, h haproxy.HAProxy)
}
}
if h.FrontendSSLOffloadEnabled(h.FrontHTTPS) || h.FrontCertsInUse() {
logger.Panic(h.FrontendEnableSSLOffload(h.FrontHTTPS, handler.CertDir, handler.alpn, handler.strictSNI))
logger.Panic(h.FrontendEnableSSLOffload(h.FrontHTTPS, handler.CertDir, handler.alpn, handler.strictSNI, handler.generateCertificates, handler.caSignFile))
}
return nil
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/handler/tcp-services.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func (handler TCPServices) createTCPFrontend(h haproxy.HAProxy, frontend models.
}))
}
if sslOffload {
errors.Add(h.FrontendEnableSSLOffload(frontend.Name, handler.CertDir, "", false))
errors.Add(h.FrontendEnableSSLOffload(frontend.Name, handler.CertDir, "", false, false, ""))
}
if errors.Result() != nil {
err = fmt.Errorf("error configuring tcp frontend: %w", err)
Expand Down Expand Up @@ -191,7 +191,7 @@ func (handler TCPServices) updateTCPFrontend(k store.K8s, h haproxy.HAProxy, fro
return err
}
if !binds[0].Ssl && p.sslOffload {
err = h.FrontendEnableSSLOffload(frontend.Name, handler.CertDir, "", false)
err = h.FrontendEnableSSLOffload(frontend.Name, handler.CertDir, "", false, false, "")
if err != nil {
err = fmt.Errorf("failed to enable SSL offload: %w", err)
return err
Expand Down
2 changes: 1 addition & 1 deletion pkg/haproxy/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ type HAProxyClient interface { //nolint:interfacebloat
FrontendsGet() (models.Frontends, error)
FrontendGet(frontendName string) (models.Frontend, error)
FrontendEdit(frontend models.FrontendBase) error
FrontendEnableSSLOffload(frontendName string, certDir string, alpn string, strictSNI bool) (err error)
FrontendEnableSSLOffload(frontendName string, certDir string, alpn string, strictSNI bool, generateCertificates bool, caSignFile string) (err error)
FrontendDisableSSLOffload(frontendName string) (err error)
FrontendSSLOffloadEnabled(frontendName string) bool
Bind
Expand Down
8 changes: 7 additions & 1 deletion pkg/haproxy/api/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,18 @@ func (c *clientNative) FrontendEdit(frontend models.FrontendBase) error {
return configuration.EditFrontend(frontend.Name, f, c.activeTransaction, 0)
}

func (c *clientNative) FrontendEnableSSLOffload(frontendName string, certDir string, alpn string, strictSNI bool) (err error) {
func (c *clientNative) FrontendEnableSSLOffload(frontendName string, certDir string, alpn string, strictSNI bool, generateCertificates bool, caSignFile string) (err error) {
binds, err := c.FrontendBindsGet(frontendName)
if err != nil {
return err
}
for _, bind := range binds {
bind.Ssl = true
bind.SslCertificate = certDir
bind.GenerateCertificates = generateCertificates
if caSignFile != "" {
bind.CaSignFile = caSignFile
}
if alpn != "" {
bind.Alpn = alpn
bind.StrictSni = strictSNI
Expand All @@ -103,8 +107,10 @@ func (c *clientNative) FrontendDisableSSLOffload(frontendName string) (err error
bind.SslCafile = ""
bind.Verify = ""
bind.SslCertificate = ""
bind.CaSignFile = ""
bind.Alpn = ""
bind.StrictSni = false
bind.GenerateCertificates = false
err = c.FrontendBindEdit(frontendName, *bind)
}
if err != nil {
Expand Down