Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow TLS sessionTicketKeys config #10284

Open
wants to merge 1 commit into
base: v2.10
Choose a base branch
from
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
70 changes: 70 additions & 0 deletions docs/content/https/tls.md
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,76 @@ spec:
- h2
```

### TLS Session Ticket Keys

_Optional_

This option allows you to specify a list of TLS Session Ticket Keys which store
the TLS connection state on the client and allow the TLS session resumption
with less overhead than re-establishing it from scratch. This is used in both
TLSv1.2 Session Tickets and TLSv1.3 PSK algorithms.

The use-case for this is 3-fold:
1. If you run a cluster of Traefik servers you can put the same Session Ticket
Keys on all servers and then a client can use it for lightweight session
re-establishment to any of the servers in the cluster. By default each
server will have its own random keys so a ticket valid for one server would
not be valid for the others.
2. Restart traefik without loosing TLS ticket validity. As the default ticket
keys are stored in memory, when Traefik restarts they will be lost. By
writing them to the config file they are persisted across restarts
3. Custom cycling and retention periods: The default daily rotation and 7-day
retention periods are not customizable. You may wish to write a cronjob to
update the Traefik config file more or less frequently, with longer or
shorter retention periods.

If you use this option you are responsible for key rotation, which should occur
at least on a daily basis or Perfect Forward Secrecy is compromised. These keys
should be stored securely or your TLS sessions may be intercepted and
decrypted.

If not specified, the default golang crypto/tls algorithm is used which is to
keep 7 days of keys and rotate on a daily basis.

These should be a list of 32-byte random strings which have been
base64-encoded. You could generate valid key strings via a command like
`openssl rand 32 | base64 -w0`. The first key will be used for creating new
tickets, so newly created keys should always be **prepended** to the list.

```yaml tab="File (YAML)"
# Dynamic configuration

tls:
options:
default:
sessionTicketKeys:
- Weh+llm9dIy/AEVGhSVuZn1Px+PeV6GgtdgjpOtEbuc=
- owcOtCw0oK1GcoFLA81BDvN0FrISKAwrkeHiII2q5YA=
- 8wN2dM+JG7XF3kYFQP33scrHlvaon0qpJTeMe7Z/ewM=
```

```toml tab="File (TOML)"
# Dynamic configuration

[tls.options]
[tls.options.default]
sessionTicketKeys = ["Weh+llm9dIy/AEVGhSVuZn1Px+PeV6GgtdgjpOtEbuc=", "owcOtCw0oK1GcoFLA81BDvN0FrISKAwrkeHiII2q5YA=", "8wN2dM+JG7XF3kYFQP33scrHlvaon0qpJTeMe7Z/ewM="]
```

```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: TLSOption
metadata:
name: default
namespace: default

spec:
sessionTicketKeys:
- Weh+llm9dIy/AEVGhSVuZn1Px+PeV6GgtdgjpOtEbuc=
- owcOtCw0oK1GcoFLA81BDvN0FrISKAwrkeHiII2q5YA=
- 8wN2dM+JG7XF3kYFQP33scrHlvaon0qpJTeMe7Z/ewM=
```

### Client Authentication (mTLS)

Traefik supports mutual authentication, through the `clientAuth` section.
Expand Down
1 change: 1 addition & 0 deletions pkg/tls/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Options struct {
SniStrict bool `json:"sniStrict,omitempty" toml:"sniStrict,omitempty" yaml:"sniStrict,omitempty" export:"true"`
PreferServerCipherSuites bool `json:"preferServerCipherSuites,omitempty" toml:"preferServerCipherSuites,omitempty" yaml:"preferServerCipherSuites,omitempty" export:"true"` // Deprecated: https://github.com/golang/go/issues/45430
ALPNProtocols []string `json:"alpnProtocols,omitempty" toml:"alpnProtocols,omitempty" yaml:"alpnProtocols,omitempty" export:"true"`
SessionTicketKeys []string `json:"sessionTicketKeys,omitempty" toml:"sessionTicketKeys,omitempty" yaml:"sessionTicketKeys,omitempty" export:"true"`
}

// SetDefaults sets the default values for an Options struct.
Expand Down
16 changes: 16 additions & 0 deletions pkg/tls/tlsmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"errors"
"fmt"
"strings"
Expand Down Expand Up @@ -399,6 +400,21 @@ func buildTLSConfig(tlsOption Options) (*tls.Config, error) {
}
}

if tlsOption.SessionTicketKeys != nil {
sessionTicketKeys := make([][32]byte, len(tlsOption.SessionTicketKeys))
for i, key := range tlsOption.SessionTicketKeys {
decoded, err := base64.StdEncoding.DecodeString(key)
if err != nil {
return nil, fmt.Errorf("invalid sessionTicketKey, must be in base64 encoding: %s", key)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return nil, fmt.Errorf("invalid sessionTicketKey, must be in base64 encoding: %s", key)
return nil, fmt.Errorf("invalid sessionTicketKey, must be base64 encoded: %s", key)

}
if len(decoded) != 32 {
return nil, fmt.Errorf("sessionTicketKey length is not 32 bytes: %s", key)
}
copy(sessionTicketKeys[i][:], decoded)
}
conf.SetSessionTicketKeys(sessionTicketKeys)
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe I'm wrong, but the SetSessionTicketKeys function could panic if the tlsOption.SessionTicketKeys is empty. To be sure you could check the length, WDYT?

}

return conf, nil
}

Expand Down