Skip to content
This repository was archived by the owner on Mar 9, 2022. It is now read-only.

Commit 4987757

Browse files
authored
Merge pull request #886 from DataDog/JulienBalestra/tls-stream
stream: can use user certificates
2 parents 9acd953 + dffd0df commit 4987757

4 files changed

Lines changed: 231 additions & 8 deletions

File tree

docs/config.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,16 @@ The explanation and default value of each configuration item are as follows:
2424
# systemd_cgroup enables systemd cgroup support.
2525
systemd_cgroup = false
2626

27-
# enable_tls_streaming enables the TLS streaming support.
27+
# enable_tls_streaming enables the TLS streaming support.
28+
# It generates a self-sign certificate unless the following x509_key_pair_streaming are both set.
2829
enable_tls_streaming = false
30+
31+
# "plugins.cri.x509_key_pair_streaming" contains a x509 valid key pair to stream with tls.
32+
[plugins.cri.x509_key_pair_streaming]
33+
# tls_cert_file is the filepath to the certificate paired with the "tls_key_file"
34+
tls_cert_file = ""
35+
# tls_key_file is the filepath to the private key paired with the "tls_cert_file"
36+
tls_key_file = ""
2937

3038
# max_container_log_line_size is the maximum log line size in bytes for a container.
3139
# Log line longer than the limit will be split into multiple lines. -1 means no

pkg/config/config.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,22 @@ type PluginConfig struct {
114114
SystemdCgroup bool `toml:"systemd_cgroup" json:"systemdCgroup"`
115115
// EnableTLSStreaming indicates to enable the TLS streaming support.
116116
EnableTLSStreaming bool `toml:"enable_tls_streaming" json:"enableTLSStreaming"`
117+
// X509KeyPairStreaming is a x509 key pair used for TLS streaming
118+
X509KeyPairStreaming `toml:"x509_key_pair_streaming" json:"x509KeyPairStreaming"`
117119
// MaxContainerLogLineSize is the maximum log line size in bytes for a container.
118120
// Log line longer than the limit will be split into multiple lines. Non-positive
119121
// value means no limit.
120122
MaxContainerLogLineSize int `toml:"max_container_log_line_size" json:"maxContainerLogSize"`
121123
}
122124

125+
// X509KeyPairStreaming contains the x509 configuration for streaming
126+
type X509KeyPairStreaming struct {
127+
// TLSCertFile is the path to a certificate file
128+
TLSCertFile string `toml:"tls_cert_file" json:"tlsCertFile"`
129+
// TLSKeyFile is the path to a private key file
130+
TLSKeyFile string `toml:"tls_key_file" json:"tlsKeyFile"`
131+
}
132+
123133
// Config contains all configurations for cri server.
124134
type Config struct {
125135
// PluginConfig is the config for CRI plugin.
@@ -152,10 +162,14 @@ func DefaultConfig() PluginConfig {
152162
},
153163
NoPivot: false,
154164
},
155-
StreamServerAddress: "127.0.0.1",
156-
StreamServerPort: "0",
157-
EnableSelinux: false,
158-
EnableTLSStreaming: false,
165+
StreamServerAddress: "127.0.0.1",
166+
StreamServerPort: "0",
167+
EnableSelinux: false,
168+
EnableTLSStreaming: false,
169+
X509KeyPairStreaming: X509KeyPairStreaming{
170+
TLSKeyFile: "",
171+
TLSCertFile: "",
172+
},
159173
SandboxImage: "k8s.gcr.io/pause:3.1",
160174
StatsCollectPeriod: 10,
161175
SystemdCgroup: false,

pkg/server/streaming.go

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,36 @@ import (
3434
ctrdutil "github.com/containerd/cri/pkg/containerd/util"
3535
)
3636

37+
type streamListenerMode int
38+
39+
const (
40+
x509KeyPairTLS streamListenerMode = iota
41+
selfSignTLS
42+
withoutTLS
43+
)
44+
45+
func getStreamListenerMode(c *criService) (streamListenerMode, error) {
46+
if c.config.EnableTLSStreaming {
47+
if c.config.X509KeyPairStreaming.TLSCertFile != "" && c.config.X509KeyPairStreaming.TLSKeyFile != "" {
48+
return x509KeyPairTLS, nil
49+
}
50+
if c.config.X509KeyPairStreaming.TLSCertFile != "" && c.config.X509KeyPairStreaming.TLSKeyFile == "" {
51+
return -1, errors.New("must set X509KeyPairStreaming.TLSKeyFile")
52+
}
53+
if c.config.X509KeyPairStreaming.TLSCertFile == "" && c.config.X509KeyPairStreaming.TLSKeyFile != "" {
54+
return -1, errors.New("must set X509KeyPairStreaming.TLSCertFile")
55+
}
56+
return selfSignTLS, nil
57+
}
58+
if c.config.X509KeyPairStreaming.TLSCertFile != "" {
59+
return -1, errors.New("X509KeyPairStreaming.TLSCertFile is set but EnableTLSStreaming is not set")
60+
}
61+
if c.config.X509KeyPairStreaming.TLSKeyFile != "" {
62+
return -1, errors.New("X509KeyPairStreaming.TLSKeyFile is set but EnableTLSStreaming is not set")
63+
}
64+
return withoutTLS, nil
65+
}
66+
3767
func newStreamServer(c *criService, addr, port string) (streaming.Server, error) {
3868
if addr == "" {
3969
a, err := k8snet.ChooseBindAddress(nil)
@@ -44,8 +74,22 @@ func newStreamServer(c *criService, addr, port string) (streaming.Server, error)
4474
}
4575
config := streaming.DefaultConfig
4676
config.Addr = net.JoinHostPort(addr, port)
47-
runtime := newStreamRuntime(c)
48-
if c.config.EnableTLSStreaming {
77+
run := newStreamRuntime(c)
78+
tlsMode, err := getStreamListenerMode(c)
79+
if err != nil {
80+
return nil, errors.Wrapf(err, "invalid stream server configuration")
81+
}
82+
switch tlsMode {
83+
case x509KeyPairTLS:
84+
tlsCert, err := tls.LoadX509KeyPair(c.config.X509KeyPairStreaming.TLSCertFile, c.config.X509KeyPairStreaming.TLSKeyFile)
85+
if err != nil {
86+
return nil, errors.Wrap(err, "failed to load x509 key pair for stream server")
87+
}
88+
config.TLSConfig = &tls.Config{
89+
Certificates: []tls.Certificate{tlsCert},
90+
}
91+
return streaming.NewServer(config, run)
92+
case selfSignTLS:
4993
tlsCert, err := newTLSCert()
5094
if err != nil {
5195
return nil, errors.Wrap(err, "failed to generate tls certificate for stream server")
@@ -54,8 +98,12 @@ func newStreamServer(c *criService, addr, port string) (streaming.Server, error)
5498
Certificates: []tls.Certificate{tlsCert},
5599
InsecureSkipVerify: true,
56100
}
101+
return streaming.NewServer(config, run)
102+
case withoutTLS:
103+
return streaming.NewServer(config, run)
104+
default:
105+
return nil, errors.New("invalid configuration for the stream listener")
57106
}
58-
return streaming.NewServer(config, runtime)
59107
}
60108

61109
type streamRuntime struct {

pkg/server/streaming_test.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
Copyright 2017 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package server
18+
19+
import (
20+
"testing"
21+
22+
"github.com/containerd/cri/pkg/config"
23+
"github.com/stretchr/testify/assert"
24+
)
25+
26+
func TestValidateStreamServer(t *testing.T) {
27+
for desc, test := range map[string]struct {
28+
*criService
29+
tlsMode streamListenerMode
30+
expectErr bool
31+
}{
32+
"should pass with default withoutTLS": {
33+
criService: &criService{
34+
config: config.Config{
35+
PluginConfig: config.DefaultConfig(),
36+
},
37+
},
38+
tlsMode: withoutTLS,
39+
expectErr: false,
40+
},
41+
"should pass with x509KeyPairTLS": {
42+
criService: &criService{
43+
config: config.Config{
44+
PluginConfig: config.PluginConfig{
45+
EnableTLSStreaming: true,
46+
X509KeyPairStreaming: config.X509KeyPairStreaming{
47+
TLSKeyFile: "non-empty",
48+
TLSCertFile: "non-empty",
49+
},
50+
},
51+
},
52+
},
53+
tlsMode: x509KeyPairTLS,
54+
expectErr: false,
55+
},
56+
"should pass with selfSign": {
57+
criService: &criService{
58+
config: config.Config{
59+
PluginConfig: config.PluginConfig{
60+
EnableTLSStreaming: true,
61+
},
62+
},
63+
},
64+
tlsMode: selfSignTLS,
65+
expectErr: false,
66+
},
67+
"should return error with X509 keypair but not EnableTLSStreaming": {
68+
criService: &criService{
69+
config: config.Config{
70+
PluginConfig: config.PluginConfig{
71+
EnableTLSStreaming: false,
72+
X509KeyPairStreaming: config.X509KeyPairStreaming{
73+
TLSKeyFile: "non-empty",
74+
TLSCertFile: "non-empty",
75+
},
76+
},
77+
},
78+
},
79+
tlsMode: -1,
80+
expectErr: true,
81+
},
82+
"should return error with X509 TLSCertFile empty": {
83+
criService: &criService{
84+
config: config.Config{
85+
PluginConfig: config.PluginConfig{
86+
EnableTLSStreaming: true,
87+
X509KeyPairStreaming: config.X509KeyPairStreaming{
88+
TLSKeyFile: "non-empty",
89+
TLSCertFile: "",
90+
},
91+
},
92+
},
93+
},
94+
tlsMode: -1,
95+
expectErr: true,
96+
},
97+
"should return error with X509 TLSKeyFile empty": {
98+
criService: &criService{
99+
config: config.Config{
100+
PluginConfig: config.PluginConfig{
101+
EnableTLSStreaming: true,
102+
X509KeyPairStreaming: config.X509KeyPairStreaming{
103+
TLSKeyFile: "",
104+
TLSCertFile: "non-empty",
105+
},
106+
},
107+
},
108+
},
109+
tlsMode: -1,
110+
expectErr: true,
111+
},
112+
"should return error without EnableTLSStreaming and only TLSCertFile set": {
113+
criService: &criService{
114+
config: config.Config{
115+
PluginConfig: config.PluginConfig{
116+
EnableTLSStreaming: false,
117+
X509KeyPairStreaming: config.X509KeyPairStreaming{
118+
TLSKeyFile: "",
119+
TLSCertFile: "non-empty",
120+
},
121+
},
122+
},
123+
},
124+
tlsMode: -1,
125+
expectErr: true,
126+
},
127+
"should return error without EnableTLSStreaming and only TLSKeyFile set": {
128+
criService: &criService{
129+
config: config.Config{
130+
PluginConfig: config.PluginConfig{
131+
EnableTLSStreaming: false,
132+
X509KeyPairStreaming: config.X509KeyPairStreaming{
133+
TLSKeyFile: "non-empty",
134+
TLSCertFile: "",
135+
},
136+
},
137+
},
138+
},
139+
tlsMode: -1,
140+
expectErr: true,
141+
},
142+
} {
143+
t.Run(desc, func(t *testing.T) {
144+
tlsMode, err := getStreamListenerMode(test.criService)
145+
if test.expectErr {
146+
assert.Error(t, err)
147+
return
148+
}
149+
assert.NoError(t, err)
150+
assert.Equal(t, test.tlsMode, tlsMode)
151+
})
152+
}
153+
}

0 commit comments

Comments
 (0)