forked from open-cluster-management-io/sdk-go
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.go
More file actions
211 lines (180 loc) · 5.91 KB
/
Copy pathconfig.go
File metadata and controls
211 lines (180 loc) · 5.91 KB
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
package tls
import (
"crypto/tls"
"fmt"
"strings"
"k8s.io/klog/v2"
)
const (
// ConfigMapName is the well-known name of the ConfigMap containing TLS profile settings.
ConfigMapName = "ocm-tls-profile"
// ConfigMapKeyMinVersion is the ConfigMap key for the minimum TLS version.
ConfigMapKeyMinVersion = "minTLSVersion"
// ConfigMapKeyCipherSuites is the ConfigMap key for cipher suites
ConfigMapKeyCipherSuites = "cipherSuites"
)
// defaultMinTLSVersion is the fallback when no TLS profile is configured
const defaultMinTLSVersion = "VersionTLS12"
// secureCiphersByName maps IANA names → IDs for ciphers in tls.CipherSuites().
var secureCiphersByName map[string]uint16
// insecureCiphersByName maps IANA names → IDs for ciphers in tls.InsecureCipherSuites().
var insecureCiphersByName map[string]uint16
// cipherNamesByID maps cipher suite IDs → IANA names for all known ciphers.
var cipherNamesByID map[uint16]string
func init() {
secure := tls.CipherSuites()
insecure := tls.InsecureCipherSuites()
secureCiphersByName = make(map[string]uint16, len(secure))
for _, s := range secure {
secureCiphersByName[s.Name] = s.ID
}
insecureCiphersByName = make(map[string]uint16, len(insecure))
for _, s := range insecure {
insecureCiphersByName[s.Name] = s.ID
}
cipherNamesByID = make(map[uint16]string, len(secure)+len(insecure))
for _, s := range secure {
cipherNamesByID[s.ID] = s.Name
}
for _, s := range insecure {
cipherNamesByID[s.ID] = s.Name
}
}
// TLSConfig represents parsed TLS configuration
type TLSConfig struct {
MinVersion uint16
CipherSuites []uint16
}
// ParseTLSVersion converts a TLS version string to the corresponding crypto/tls constant.
// Accepted formats: "VersionTLS10"/"TLSv1.0" through "VersionTLS13"/"TLSv1.3".
// An empty string defaults to TLS 1.2.
func ParseTLSVersion(version string) (uint16, error) {
version = strings.TrimSpace(version)
switch version {
case "VersionTLS10", "TLSv1.0":
return tls.VersionTLS10, nil
case "VersionTLS11", "TLSv1.1":
return tls.VersionTLS11, nil
case "VersionTLS12", "TLSv1.2", "":
// Empty string defaults to TLS 1.2
return tls.VersionTLS12, nil
case "VersionTLS13", "TLSv1.3":
return tls.VersionTLS13, nil
default:
return 0, fmt.Errorf("unknown TLS version: %s", version)
}
}
// ParseCipherSuites converts IANA cipher suite names to Go crypto/tls constants.
// Secure ciphers (tls.CipherSuites) are accepted silently. Insecure ciphers
// (tls.InsecureCipherSuites) are accepted but logged as a warning.
// Returns a list of cipher suite IDs and a list of unrecognized cipher names.
func ParseCipherSuites(cipherString string) ([]uint16, []string) {
if strings.TrimSpace(cipherString) == "" {
return nil, nil
}
cipherNames := strings.Split(cipherString, ",")
cipherSuites := make([]uint16, 0, len(cipherNames))
unsupported := make([]string, 0)
for _, name := range cipherNames {
name = strings.TrimSpace(name)
if name == "" {
continue
}
if id, ok := secureCiphersByName[name]; ok {
cipherSuites = append(cipherSuites, id)
continue
}
if id, ok := insecureCiphersByName[name]; ok {
klog.Warningf("Cipher suite %s is insecure and should not be used in production", name)
cipherSuites = append(cipherSuites, id)
continue
}
unsupported = append(unsupported, name)
}
return cipherSuites, unsupported
}
// GetDefaultTLSConfig returns a TLS config with safe defaults (TLS 1.2)
func GetDefaultTLSConfig() *TLSConfig {
return &TLSConfig{
MinVersion: tls.VersionTLS12,
CipherSuites: nil, // Use Go's default cipher suites for TLS 1.2
}
}
// ConfigFromFlags creates TLS config from command-line flags
func ConfigFromFlags(minVersion, cipherSuites string) (*TLSConfig, error) {
minVersion = strings.TrimSpace(minVersion)
cipherSuites = strings.TrimSpace(cipherSuites)
if minVersion == "" && cipherSuites == "" {
return nil, nil // No flags provided
}
cfg := &TLSConfig{}
// Parse min version
if minVersion != "" {
ver, err := ParseTLSVersion(minVersion)
if err != nil {
return nil, fmt.Errorf("invalid --tls-min-version: %w", err)
}
cfg.MinVersion = ver
} else {
cfg.MinVersion = tls.VersionTLS12
}
// Parse cipher suites
if cipherSuites != "" {
suites, unsupported := ParseCipherSuites(cipherSuites)
if len(unsupported) > 0 {
return nil, fmt.Errorf("unsupported cipher suites: %v", unsupported)
}
cfg.CipherSuites = suites
}
return cfg, nil
}
// VersionToString converts a TLS version constant to its string representation
func VersionToString(version uint16) string {
switch version {
case tls.VersionTLS10:
return "VersionTLS10"
case tls.VersionTLS11:
return "VersionTLS11"
case tls.VersionTLS12:
return "VersionTLS12"
case tls.VersionTLS13:
return "VersionTLS13"
default:
return fmt.Sprintf("Unknown (0x%04x)", version)
}
}
// CipherSuitesToString converts cipher suite IDs back to IANA names
func CipherSuitesToString(suites []uint16) string {
if len(suites) == 0 {
return ""
}
names := make([]string, 0, len(suites))
for _, suite := range suites {
name := cipherIDToName(suite)
if name != "" {
names = append(names, name)
}
}
return strings.Join(names, ",")
}
// ConfigToFunc returns a function that applies the TLS configuration to a tls.Config.
// It is suitable for use with controller-runtime's TLSOpts (webhook/metrics servers).
// If tlsCfg is nil (e.g. returned by ConfigFromFlags when no flags are set), the
// returned function is a no-op that leaves the tls.Config unchanged.
func ConfigToFunc(tlsCfg *TLSConfig) func(*tls.Config) {
if tlsCfg == nil {
return func(*tls.Config) {}
}
return func(config *tls.Config) {
config.MinVersion = tlsCfg.MinVersion
if tlsCfg.MinVersion == tls.VersionTLS13 {
config.MaxVersion = tls.VersionTLS13
} else if len(tlsCfg.CipherSuites) > 0 {
config.CipherSuites = tlsCfg.CipherSuites
}
}
}
// cipherIDToName converts a cipher suite ID to its IANA name.
func cipherIDToName(id uint16) string {
return cipherNamesByID[id]
}