1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
package tls
import (
"crypto/tls"
"gitlab.com/gitlab-org/gitlab-pages/internal/config"
"gitlab.com/gitlab-org/gitlab-pages/internal/feature"
"gitlab.com/gitlab-org/gitlab-pages/internal/ratelimiter"
"gitlab.com/gitlab-org/gitlab-pages/metrics"
)
var preferredCipherSuites = []uint16{
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_AES_128_GCM_SHA256,
tls.TLS_AES_256_GCM_SHA384,
tls.TLS_CHACHA20_POLY1305_SHA256,
}
// GetCertificateFunc returns the certificate to be used for given domain
type GetCertificateFunc func(*tls.ClientHelloInfo) (*tls.Certificate, error)
// GetTLSConfig initializes tls.Config based on config flags
// getCertificateByServerName obtains certificate based on domain
func GetTLSConfig(cfg *config.Config, getCertificateByServerName GetCertificateFunc) (*tls.Config, error) {
certificate, err := tls.X509KeyPair(cfg.General.RootCertificate, cfg.General.RootKey)
if err != nil {
return nil, err
}
getCertificate := func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
// Golang calls tls.Config.GetCertificate only if it's set and
// 1. ServerName != ""
// 2. Or tls.Config.Certificates is empty array
// tls.Config.Certificates contain wildcard certificate
// We want to implement rate limits via GetCertificate, so we need to call it every time
// So we don't set tls.Config.Certificates, but simulate the behavior of golang:
// 1. try to get certificate by name
// 2. if we can't, fallback to default(wildcard) certificate
cert, err := getCertificateByServerName(info)
if cert != nil || err != nil {
return cert, err
}
return &certificate, nil
}
TLSDomainRateLimiter := ratelimiter.New(
"tls_connections_by_domain",
ratelimiter.WithTLSKeyFunc(ratelimiter.TLSHostnameKey),
ratelimiter.WithCacheMaxSize(ratelimiter.DefaultDomainCacheSize),
ratelimiter.WithCachedEntriesMetric(metrics.RateLimitCachedEntries),
ratelimiter.WithCachedRequestsMetric(metrics.RateLimitCacheRequests),
ratelimiter.WithBlockedCountMetric(metrics.RateLimitBlockedCount),
ratelimiter.WithLimitPerSecond(cfg.RateLimit.TLSDomainLimitPerSecond),
ratelimiter.WithBurstSize(cfg.RateLimit.TLSDomainBurst),
ratelimiter.WithEnforce(feature.EnforceDomainTLSRateLimits.Enabled()),
)
TLSSourceIPRateLimiter := ratelimiter.New(
"tls_connections_by_source_ip",
ratelimiter.WithTLSKeyFunc(ratelimiter.TLSClientIPKey),
ratelimiter.WithCacheMaxSize(ratelimiter.DefaultSourceIPCacheSize),
ratelimiter.WithCachedEntriesMetric(metrics.RateLimitCachedEntries),
ratelimiter.WithCachedRequestsMetric(metrics.RateLimitCacheRequests),
ratelimiter.WithBlockedCountMetric(metrics.RateLimitBlockedCount),
ratelimiter.WithLimitPerSecond(cfg.RateLimit.TLSSourceIPLimitPerSecond),
ratelimiter.WithBurstSize(cfg.RateLimit.TLSSourceIPBurst),
ratelimiter.WithEnforce(feature.EnforceIPTLSRateLimits.Enabled()),
)
getCertificate = TLSDomainRateLimiter.GetCertificateMiddleware(getCertificate)
getCertificate = TLSSourceIPRateLimiter.GetCertificateMiddleware(getCertificate)
// set MinVersion to fix gosec: G402
tlsConfig := &tls.Config{GetCertificate: getCertificate, MinVersion: tls.VersionTLS12}
if !cfg.General.InsecureCiphers {
configureTLSCiphers(tlsConfig)
}
tlsConfig.MinVersion = cfg.TLS.MinVersion
tlsConfig.MaxVersion = cfg.TLS.MaxVersion
return tlsConfig, nil
}
func configureTLSCiphers(tlsConfig *tls.Config) {
tlsConfig.PreferServerCipherSuites = true
tlsConfig.CipherSuites = preferredCipherSuites
}
|