teleport/lib/service/cfg.go

349 lines
11 KiB
Go
Raw Normal View History

2015-10-31 18:56:49 +00:00
/*
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/base64"
"encoding/json"
"io/ioutil"
"strings"
2015-12-02 18:51:32 +00:00
"github.com/gravitational/teleport/lib/ratelimiter"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/utils"
2015-10-20 21:09:25 +00:00
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/gravitational/configure"
2015-10-30 23:57:57 +00:00
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/gravitational/configure/cstrings"
"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/gravitational/trace"
)
func ParseYAMLFile(path string, cfg interface{}) error {
bytes, err := ioutil.ReadFile(path)
if err != nil {
return trace.Wrap(err)
}
2015-10-20 21:09:07 +00:00
rendered, err := renderTemplate(bytes)
if err != nil {
return trace.Wrap(err)
}
2015-10-20 21:09:07 +00:00
return configure.ParseYAML(rendered, cfg)
}
func ParseEnv(cfg interface{}) error {
return configure.ParseEnv(cfg)
}
type Config struct {
Log LogConfig `yaml:"log"`
DataDir string `yaml:"data_dir" env:"TELEPORT_DATA_DIR"`
Hostname string `yaml:"hostname" env:"TELEPORT_HOSTNAME"`
AuthServers NetAddrSlice `yaml:"auth_servers,flow" env:"TELEPORT_AUTH_SERVERS"`
// SSH role an SSH endpoint server
SSH SSHConfig `yaml:"ssh"`
// Auth server authentication and authorizatin server config
Auth AuthConfig `yaml:"auth"`
// ReverseTunnnel role creates and mantains outbound SSH reverse tunnel to the proxy
ReverseTunnel ReverseTunnelConfig `yaml:"reverse_tunnel"`
// Proxy is SSH proxy that manages incoming and outbound connections
// via multiple reverse tunnels
Proxy ProxyConfig `yaml:"proxy"`
}
2015-10-27 00:58:39 +00:00
func (cfg *Config) RoleConfig() RoleConfig {
return RoleConfig{
DataDir: cfg.DataDir,
Hostname: cfg.Hostname,
AuthServers: cfg.AuthServers,
Auth: cfg.Auth,
}
}
type LogConfig struct {
Output string `yaml:"output" env:"TELEPORT_LOG_OUTPUT"`
Severity string `yaml:"severity" env:"TELEPORT_LOG_SEVERITY"`
}
type ProxyConfig struct {
// Enabled turns proxy role on or off for this process
Enabled bool `yaml:"enabled" env:"TELEPORT_PROXY_ENABLED"`
// Token is a provisioning token for new proxy server registering with auth
Token string `yaml:"token" env:"TELEPORT_PROXY_TOKEN"`
// ReverseTunnelListenAddr is address where reverse tunnel dialers connect to
ReverseTunnelListenAddr utils.NetAddr `yaml:"reverse_tunnel_listen_addr" env:"TELEPORT_PROXY_REVERSE_TUNNEL_LISTEN_ADDR"`
// WebAddr is address for web portal of the proxy
WebAddr utils.NetAddr `yaml:"web_addr" env:"TELEPORT_PROXY_WEB_ADDR"`
2015-11-02 21:02:34 +00:00
// SSHAddr is address of ssh proxy
SSHAddr utils.NetAddr `yaml:"ssh_addr" env:"TELEPORT_PROXY_SSH_ADDR"`
// AssetsDir is a directory with proxy website assets
AssetsDir string `yaml:"assets_dir" env:"TELEPORT_PROXY_ASSETS_DIR"`
// TLSKey is a base64 encoded private key used by web portal
TLSKey string `yaml:"tls_key" env:"TELEPORT_PROXY_TLS_KEY"`
// TLSCert is a base64 encoded certificate used by web portal
TLSCert string `yaml:"tlscert" env:"TELEPORT_PROXY_TLS_CERT"`
2015-12-02 18:51:32 +00:00
RateLimiter ratelimiter.RateLimiterConfig `yaml:"rate_limiter"`
}
type AuthConfig struct {
// Enabled turns auth role on or off for this process
Enabled bool `yaml:"enabled" env:"TELEPORT_AUTH_ENABLED"`
// SSHAddr is the listening address of SSH tunnel to HTTP service
SSHAddr utils.NetAddr `yaml:"ssh_addr" env:"TELEPORT_AUTH_SSH_ADDR"`
// HostAuthorityDomain is Host Certificate Authority domain name
HostAuthorityDomain string `yaml:"host_authority_domain" env:"TELEPORT_AUTH_HOST_AUTHORITY_DOMAIN"`
// Token is a provisioning token for new auth server joining the cluster
Token string `yaml:"token" env:"TELEPORT_AUTH_TOKEN"`
// SecretKey is an encryption key for secret service, will be used
// to initialize secret service if set
SecretKey string `yaml:"secret_key" env:"TELEPORT_AUTH_SECRET_KEY"`
// AllowedTokens is a set of tokens that will be added as trusted
AllowedTokens KeyVal `yaml:"allowed_tokens" env:"TELEPORT_AUTH_ALLOWED_TOKENS"`
// TrustedAuthorities is a set of trusted user certificate authorities
TrustedAuthorities RemoteCerts `yaml:"trusted_authorities" env:"TELEPORT_AUTH_TRUSTED_AUTHORITIES"`
// 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 CertificateAuthority `yaml:"user_ca_keypair" env:"TELEPORT_AUTH_USER_CA_KEYPAIR"`
// 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 CertificateAuthority `yaml:"host_ca_keypair" env:"TELEPORT_AUTH_HOST_CA_KEYPAIR"`
// KeysBackend configures backend that stores encryption keys
KeysBackend struct {
// Type is a backend type - etcd or boltdb
Type string `yaml:"type" env:"TELEPORT_AUTH_KEYS_BACKEND_TYPE"`
// Params is map with backend specific parameters
Params KeyVal `yaml:"params,flow" env:"TELEPORT_AUTH_KEYS_BACKEND_PARAMS"`
// AdditionalKey is a additional signing GPG key
AdditionalKey string `yaml:"additional_key" env:"TELEPORT_AUTH_KEYS_BACKEND_ADDITIONAL_KEY"`
} `yaml:"keys_backend"`
// EventsBackend configures backend that stores cluster events (login attempts, etc)
EventsBackend struct {
// Type is a backend type, etcd or bolt
Type string `yaml:"type" env:"TELEPORT_AUTH_EVENTS_BACKEND_TYPE"`
// Params is map with backend specific parameters
Params KeyVal `yaml:"params,flow" env:"TELEPORT_AUTH_EVENTS_BACKEND_PARAMS"`
} `yaml:"events_backend"`
// RecordsBackend configures backend that stores live SSH sessions recordings
RecordsBackend struct {
// Type is a backend type, currently only bolt
Type string `yaml:"type" env:"TELEPORT_AUTH_RECORDS_BACKEND_TYPE"`
// Params is map with backend specific parameters
Params KeyVal `yaml:"params,flow" env:"TELEPORT_AUTH_RECORDS_BACKEND_PARAMS"`
} `yaml:"records_backend"`
2015-12-02 18:51:32 +00:00
RateLimiter ratelimiter.RateLimiterConfig `yaml:"rate_limiter"`
}
// SSHConfig configures SSH server node role
type SSHConfig struct {
2015-12-02 18:51:32 +00:00
Enabled bool `yaml:"enabled" env:"TELEPORT_SSH_ENABLED"`
Token string `yaml:"token" env:"TELEPORT_SSH_TOKEN"`
Addr utils.NetAddr `yaml:"addr" env:"TELEPORT_SSH_ADDR"`
Shell string `yaml:"shell" env:"TELEPORT_SSH_SHELL"`
RateLimiter ratelimiter.RateLimiterConfig `yaml:"rate_limiter"`
}
// ReverseTunnelConfig configures reverse tunnel role
type ReverseTunnelConfig struct {
2015-12-02 18:51:32 +00:00
Enabled bool `yaml:"enabled" env:"TELEPORT_REVERSE_TUNNEL_ENABLED"`
Token string `yaml:"token" env:"TELEPORT_REVERSE_TUNNEL_TOKEN"`
DialAddr utils.NetAddr `yaml:"dial_addr" env:"TELEPORT_REVERSE_TUNNEL_DIAL_ADDR"`
RateLimiter ratelimiter.RateLimiterConfig `yaml:"rate_limiter"`
}
type NetAddrSlice []utils.NetAddr
func (s *NetAddrSlice) Set(val string) error {
2015-10-30 23:57:57 +00:00
values := cstrings.SplitComma(val)
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)
}
2015-10-30 23:57:57 +00:00
for _, i := range cstrings.SplitComma(v) {
vals := strings.SplitN(i, ":", 2)
if len(vals) != 2 {
return trace.Errorf("extra options should be defined like KEY:VAL")
}
(*kv)[vals[0]] = vals[1]
}
return nil
}
type RemoteCert struct {
Type string `json:"type"`
ID string `json:"id"`
DomainName string `json:"domain_name" yaml:"domain_name" env:"domain_name"`
Value string `json:"value"`
}
type RemoteCerts []RemoteCert
func (c *RemoteCerts) SetEnv(v string) error {
var certs []RemoteCert
if err := json.Unmarshal([]byte(v), &certs); err != nil {
return trace.Wrap(err, "expected JSON encoded remote certificate")
}
*c = certs
return nil
}
type CertificateAuthority struct {
PublicKey string `json:"public" yaml:"public"`
PrivateKey string `json:"private" yaml:"private"`
}
func (c *CertificateAuthority) SetEnv(v string) error {
var ca CertificateAuthority
if err := json.Unmarshal([]byte(v), &ca); err != nil {
return trace.Wrap(err, "expected JSON encoded certificate authority")
}
key, err := base64.StdEncoding.DecodeString(ca.PrivateKey)
if err != nil {
return trace.Wrap(err, "private key should be base64 encoded")
}
c.PublicKey = ca.PublicKey
c.PrivateKey = string(key)
2015-10-26 21:36:52 +00:00
if c.PrivateKey == "" || c.PublicKey == "" {
return trace.Errorf("both public key and private key should be setup")
}
return nil
}
func (c *CertificateAuthority) UnmarshalYAML(unmarshal func(interface{}) error) error {
var ca struct {
PublicKey string `json:"public" yaml:"public"`
PrivateKey string `json:"private" yaml:"private"`
}
if err := unmarshal(&ca); err != nil {
return trace.Wrap(err)
}
key, err := base64.StdEncoding.DecodeString(ca.PrivateKey)
if err != nil {
return trace.Wrap(err, "private key should be base64 encoded")
}
c.PublicKey = ca.PublicKey
c.PrivateKey = string(key)
2015-10-26 21:36:52 +00:00
if c.PrivateKey == "" || c.PublicKey == "" {
return trace.Errorf("both public key and private key should be setup")
}
return nil
}
func (c *CertificateAuthority) ToCA() *services.LocalCertificateAuthority {
return &services.LocalCertificateAuthority{
CertificateAuthority: services.CertificateAuthority{
PublicKey: []byte(c.PublicKey),
},
PrivateKey: []byte(c.PrivateKey),
}
}
func convertRemoteCerts(inCerts RemoteCerts) []services.CertificateAuthority {
outCerts := make([]services.CertificateAuthority, len(inCerts))
for i, v := range inCerts {
outCerts[i] = services.CertificateAuthority{
ID: v.ID,
DomainName: v.DomainName,
Type: v.Type,
PublicKey: []byte(v.Value),
}
}
return outCerts
}
func SetDefaults(cfg *Config) {
if cfg.Log.Output == "" {
cfg.Log.Output = "console"
}
if cfg.Log.Severity == "" {
cfg.Log.Severity = "INFO"
}
if cfg.SSH.Addr.IsEmpty() {
cfg.SSH.Addr = utils.NetAddr{
Network: "tcp",
Addr: "127.0.0.1:33001",
}
}
if cfg.SSH.Shell == "" {
cfg.SSH.Shell = "/bin/bash"
}
if cfg.Auth.SSHAddr.IsEmpty() {
cfg.Auth.SSHAddr = utils.NetAddr{
Network: "tcp",
Addr: "127.0.0.1:33000",
}
}
if cfg.Proxy.ReverseTunnelListenAddr.IsEmpty() {
cfg.Proxy.ReverseTunnelListenAddr = utils.NetAddr{
Network: "tcp",
Addr: "127.0.0.1:33006",
}
}
if cfg.Proxy.WebAddr.IsEmpty() {
cfg.Proxy.WebAddr = utils.NetAddr{
Network: "tcp",
Addr: "127.0.0.1:33007",
}
}
if cfg.Proxy.SSHAddr.IsEmpty() {
cfg.Proxy.SSHAddr = utils.NetAddr{
Network: "tcp",
Addr: "127.0.0.1:33008",
}
}
}