forked from gravitational/teleport
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cfg.go
382 lines (315 loc) · 10.7 KB
/
cfg.go
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
/*
Copyright 2015 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package service
import (
"encoding/json"
"fmt"
"io"
"net"
"os"
"path/filepath"
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/lib/backend/etcdbk"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/limiter"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/utils"
log "github.com/Sirupsen/logrus"
"github.com/gravitational/trace"
"gopkg.in/yaml.v2"
)
// Config structure is used to initialize _all_ services Teleporot can run.
// Some settings are globl (like DataDir) while others are grouped into
// sections, like AuthConfig
type Config struct {
DataDir string
Hostname string
// AuthServers is a list of auth servers nodes, proxies and peer auth servers
// connect to
AuthServers NetAddrSlice
// AdvertiseIP is used to "publish" an alternative IP address this node
// can be reached on, if running behind NAT
AdvertiseIP net.IP
// SSH role an SSH endpoint server
SSH SSHConfig
// Auth server authentication and authorizatin server config
Auth AuthConfig
// Proxy is SSH proxy that manages incoming and outbound connections
// via multiple reverse tunnels
Proxy ProxyConfig
// Unique UUID of this host (it will be known via this UUID within
// a teleport cluster). It's automatically generated on 1st start
HostUUID string
// Console writer to speak to a user
Console io.Writer
}
// ApplyToken assigns a given token to all internal services but only if token
// is not an empty string.
//
// Returns 'true' if token was modified
func (cfg *Config) ApplyToken(token string) bool {
if token != "" {
cfg.SSH.Token = token
cfg.Proxy.Token = token
cfg.Auth.Token = token
return true
}
return false
}
// ConfigureBolt configures Bolt back-ends with a data dir.
func (cfg *Config) ConfigureBolt(dataDir string) {
a := &cfg.Auth
if a.EventsBackend.Type == teleport.BoltBackendType {
a.EventsBackend.Params = boltParams(dataDir, defaults.EventsBoltFile)
}
if a.KeysBackend.Type == teleport.BoltBackendType {
a.KeysBackend.Params = boltParams(dataDir, defaults.KeysBoltFile)
}
if a.RecordsBackend.Type == teleport.BoltBackendType {
a.RecordsBackend.Params = boltParams(dataDir, defaults.RecordsBoltFile)
}
}
// ConfigureETCD configures ETCD backend (still uses BoltDB for some cases)
func (cfg *Config) ConfigureETCD(dataDir string, etcdCfg etcdbk.Config) error {
a := &cfg.Auth
params, err := etcdParams(etcdCfg)
if err != nil {
return trace.Wrap(err)
}
a.KeysBackend.Type = teleport.ETCDBackendType
a.KeysBackend.Params = params
// We can't store records and events in ETCD
a.EventsBackend.Type = teleport.BoltBackendType
a.EventsBackend.Params = boltParams(dataDir, defaults.EventsBoltFile)
a.RecordsBackend.Type = teleport.BoltBackendType
a.RecordsBackend.Params = boltParams(dataDir, defaults.RecordsBoltFile)
return nil
}
// RoleConfig is a config for particular Teleport role
func (cfg *Config) RoleConfig() RoleConfig {
return RoleConfig{
DataDir: cfg.DataDir,
HostUUID: cfg.HostUUID,
HostName: cfg.Hostname,
AuthServers: cfg.AuthServers,
Auth: cfg.Auth,
Console: cfg.Console,
}
}
// DebugDumpToYAML is useful for debugging: it dumps the Config structure into
// a string
func (cfg *Config) DebugDumpToYAML() string {
out, err := yaml.Marshal(cfg)
if err != nil {
return err.Error()
}
return string(out)
}
type ProxyConfig struct {
// Enabled turns proxy role on or off for this process
Enabled bool
// Token is a provisioning token for new proxy server registering with auth
Token string
// ReverseTunnelListenAddr is address where reverse tunnel dialers connect to
ReverseTunnelListenAddr utils.NetAddr
// WebAddr is address for web portal of the proxy
WebAddr utils.NetAddr
// SSHAddr is address of ssh proxy
SSHAddr utils.NetAddr
// AssetsDir is a directory with proxy website assets
AssetsDir string
// TLSKey is a base64 encoded private key used by web portal
TLSKey string
// TLSCert is a base64 encoded certificate used by web portal
TLSCert string
Limiter limiter.LimiterConfig
}
type AuthConfig struct {
// Enabled turns auth role on or off for this process
Enabled bool
// SSHAddr is the listening address of SSH tunnel to HTTP service
SSHAddr utils.NetAddr
// Token is a provisioning token for an additonal auth server joining the cluster
Token string
// SecretKey is an encryption key for secret service, will be used
// to initialize secret service if set
SecretKey string
// AllowedTokens is a set of tokens that will be added as trusted
AllowedTokens KeyVal
// TrustedAuthorities is a set of trusted user certificate authorities
TrustedAuthorities CertificateAuthorities
// DomainName is a name that identifies this authority and all
// host nodes in the cluster that will share this authority domain name
// as a base name, e.g. if authority domain name is example.com,
// all nodes in the cluster will have UUIDs in the form: <uuid>.example.com
DomainName string
// UserCA allows to pass preconfigured user certificate authority keypair
// to auth server so it will use it on the first start instead of generating
// a new keypair
UserCA LocalCertificateAuthority
// HostCA allows to pass preconfigured host certificate authority keypair
// to auth server so it will use it on the first start instead of generating
// a new keypair
HostCA LocalCertificateAuthority
// KeysBackend configures backend that stores auth keys, certificates, tokens ...
KeysBackend struct {
// Type is a backend type - etcd or boltdb
Type string
// Params is map with backend specific parameters
Params string
}
// EventsBackend configures backend that stores cluster events (login attempts, etc)
EventsBackend struct {
// Type is a backend type, etcd or bolt
Type string
// Params is map with backend specific parameters
Params string
}
// RecordsBackend configures backend that stores live SSH sessions recordings
RecordsBackend struct {
// Type is a backend type, currently only bolt
Type string
// Params is map with backend specific parameters
Params string
}
Limiter limiter.LimiterConfig
}
// SSHConfig configures SSH server node role
type SSHConfig struct {
Enabled bool
Token string
Addr utils.NetAddr
Shell string
Limiter limiter.LimiterConfig
Labels map[string]string
CmdLabels services.CommandLabels
}
type NetAddrSlice []utils.NetAddr
func (s *NetAddrSlice) Set(val string) error {
values := make([]string, 0)
err := json.Unmarshal([]byte(val), &values)
if err != nil {
return trace.Wrap(err)
}
out := make([]utils.NetAddr, len(values))
for i, v := range values {
a, err := utils.ParseAddr(v)
if err != nil {
return trace.Wrap(err)
}
out[i] = *a
}
*s = out
return nil
}
type KeyVal map[string]string
// Set accepts string with arguments in the form "key:val,key2:val2"
func (kv *KeyVal) Set(v string) error {
if len(*kv) == 0 {
*kv = make(map[string]string)
}
err := json.Unmarshal([]byte(v), kv)
if err != nil {
return trace.Wrap(err)
}
return nil
}
type CertificateAuthority struct {
Type string `json:"type"`
ID string `json:"id"`
DomainName string `json:"domain_name"`
PublicKey string `json:"public_key"`
}
type CertificateAuthorities []CertificateAuthority
func (c *CertificateAuthorities) SetEnv(v string) error {
var certs []CertificateAuthority
if err := json.Unmarshal([]byte(v), &certs); err != nil {
return trace.Wrap(err, "expected JSON encoded remote certificate")
}
*c = certs
return nil
}
func (a CertificateAuthorities) Authorities() ([]services.CertAuthority, error) {
return nil, nil
}
type LocalCertificateAuthority struct {
CertificateAuthority `json:"public"`
PrivateKey string `json:"private_key"`
}
func (c *LocalCertificateAuthority) SetEnv(v string) error {
var ca *LocalCertificateAuthority
if err := json.Unmarshal([]byte(v), &ca); err != nil {
return trace.Wrap(err, "expected JSON encoded certificate authority")
}
*c = *ca
return nil
}
func (c *LocalCertificateAuthority) CA() (*services.CertAuthority, error) {
return nil, nil
}
// MakeDefaultConfig() creates a new Config structure and populates it with defaults
func MakeDefaultConfig() (config *Config) {
config = &Config{}
ApplyDefaults(config)
return config
}
// ApplyDefaults applies default values to the existing config structure
func ApplyDefaults(cfg *Config) {
hostname, err := os.Hostname()
if err != nil {
hostname = "localhost"
log.Errorf("Failed to determine hostname: %v", err)
}
// defaults for the auth service:
cfg.Auth.Enabled = true
cfg.Auth.SSHAddr = *defaults.AuthListenAddr()
cfg.Auth.EventsBackend.Type = defaults.BackendType
cfg.Auth.EventsBackend.Params = boltParams(defaults.DataDir, defaults.EventsBoltFile)
cfg.Auth.KeysBackend.Type = defaults.BackendType
cfg.Auth.KeysBackend.Params = boltParams(defaults.DataDir, defaults.KeysBoltFile)
cfg.Auth.RecordsBackend.Type = defaults.BackendType
cfg.Auth.RecordsBackend.Params = boltParams(defaults.DataDir, defaults.RecordsBoltFile)
defaults.ConfigureLimiter(&cfg.Auth.Limiter)
// defaults for the SSH proxy service:
cfg.Proxy.Enabled = true
cfg.Proxy.AssetsDir = defaults.DataDir
cfg.Proxy.SSHAddr = *defaults.ProxyListenAddr()
cfg.Proxy.WebAddr = *defaults.ProxyWebListenAddr()
cfg.Proxy.ReverseTunnelListenAddr = *defaults.ReverseTunnellListenAddr()
defaults.ConfigureLimiter(&cfg.Proxy.Limiter)
// defaults for the SSH service:
cfg.SSH.Enabled = true
cfg.SSH.Addr = *defaults.SSHServerListenAddr()
cfg.SSH.Shell = defaults.DefaultShell
defaults.ConfigureLimiter(&cfg.SSH.Limiter)
// global defaults
cfg.Hostname = hostname
cfg.DataDir = defaults.DataDir
if cfg.Auth.Enabled {
cfg.AuthServers = []utils.NetAddr{cfg.Auth.SSHAddr}
}
cfg.Console = os.Stdout
}
// Generates a string accepted by the BoltDB driver, like this:
// `{"path": "/var/lib/teleport/records.db"}`
func boltParams(storagePath, dbFile string) string {
return fmt.Sprintf(`{"path": "%s"}`, filepath.Join(storagePath, dbFile))
}
// etcdParams generates a string accepted by the ETCD driver, like this:
func etcdParams(cfg etcdbk.Config) (string, error) {
out, err := json.Marshal(cfg)
if err != nil { // don't know what to do seriously
return "", trace.Wrap(err)
}
return string(out), nil
}