Skip to content

Commit

Permalink
Add --public-addr --cert-file --key-file for teleport configure (#9049)
Browse files Browse the repository at this point in the history
  • Loading branch information
greedy52 authored Nov 18, 2021
1 parent 4d574ea commit 778168d
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 28 deletions.
121 changes: 95 additions & 26 deletions lib/config/configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,35 +107,104 @@ func TestMain(m *testing.M) {
os.Exit(res)
}

func TestConfig(t *testing.T) {
t.Run("SampleConfig", func(t *testing.T) {
// generate sample config and write it into a temp file:
sfc, err := MakeSampleFileConfig(SampleFlags{
ClusterName: "cookie.localhost",
ACMEEnabled: true,
ACMEEmail: "[email protected]",
LicensePath: "/tmp/license.pem",
})
require.NoError(t, err)
require.NotNil(t, sfc)
fn := filepath.Join(t.TempDir(), "default-config.yaml")
err = os.WriteFile(fn, []byte(sfc.DebugDumpToYAML()), 0660)
require.NoError(t, err)
func TestSampleConfig(t *testing.T) {
testCases := []struct {
name string
input SampleFlags
expectError bool
expectClusterName ClusterName
expectLicenseFile string
expectProxyPublicAddrs apiutils.Strings
expectProxyWebAddr string
expectProxyKeyPairs []KeyPair
}{
{
name: "ACMEEnabled",
input: SampleFlags{
ClusterName: "cookie.localhost",
ACMEEnabled: true,
ACMEEmail: "[email protected]",
LicensePath: "/tmp/license.pem",
},
expectClusterName: ClusterName("cookie.localhost"),
expectLicenseFile: "/tmp/license.pem",
expectProxyPublicAddrs: apiutils.Strings{"cookie.localhost:443"},
expectProxyWebAddr: "0.0.0.0:443",
},
{
name: "public addrs",
input: SampleFlags{
PublicAddrs: []string{"tele.example.com:443"},
},
expectProxyPublicAddrs: apiutils.Strings{"tele.example.com:443"},
},
{
name: "key file missing",
input: SampleFlags{
CertFile: "/var/lib/teleport/fullchain.pem",
},
expectError: true,
},
{
name: "load x509 key pair failed",
input: SampleFlags{
KeyFile: "/var/lib/teleport/key.pem",
CertFile: "/var/lib/teleport/fullchain.pem",
},
expectError: true,
},
{
name: "cluster name missing",
input: SampleFlags{
ACMEEnabled: true,
},
expectError: true,
},
{
name: "ACMEEnabled conflict with key file",
input: SampleFlags{
ClusterName: "cookie.localhost",
ACMEEnabled: true,
KeyFile: "/var/lib/teleport/privkey.pem",
CertFile: "/var/lib/teleport/fullchain.pem",
},
expectError: true,
},
}

// make sure it could be parsed:
fc, err := ReadFromFile(fn)
require.NoError(t, err)
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
sfc, err := MakeSampleFileConfig(testCase.input)

if testCase.expectError {
require.Error(t, err)
require.Nil(t, sfc)
return
}

// validate a couple of values:
require.Equal(t, defaults.DataDir, fc.Global.DataDir)
require.Equal(t, "INFO", fc.Logger.Severity)
require.Equal(t, fc.Auth.ClusterName, ClusterName("cookie.localhost"))
require.Equal(t, fc.Auth.LicenseFile, "/tmp/license.pem")
require.Equal(t, fc.Proxy.PublicAddr, apiutils.Strings{"cookie.localhost:443"})
require.Equal(t, fc.Proxy.WebAddr, "0.0.0.0:443")
require.NoError(t, err)
require.NotNil(t, sfc)

require.False(t, lib.IsInsecureDevMode())
})
fn := filepath.Join(t.TempDir(), "default-config.yaml")
err = os.WriteFile(fn, []byte(sfc.DebugDumpToYAML()), 0660)
require.NoError(t, err)

// make sure it could be parsed:
fc, err := ReadFromFile(fn)
require.NoError(t, err)

// validate a couple of values:
require.Equal(t, fc.Global.DataDir, defaults.DataDir)
require.Equal(t, fc.Logger.Severity, "INFO")
require.Equal(t, testCase.expectClusterName, fc.Auth.ClusterName)
require.Equal(t, testCase.expectLicenseFile, fc.Auth.LicenseFile)
require.Equal(t, testCase.expectProxyWebAddr, fc.Proxy.WebAddr)
require.ElementsMatch(t, testCase.expectProxyPublicAddrs, fc.Proxy.PublicAddr)
require.ElementsMatch(t, testCase.expectProxyKeyPairs, fc.Proxy.KeyPairs)

require.False(t, lib.IsInsecureDevMode())
})
}
}

// TestBooleanParsing tests that boolean options
Expand Down
33 changes: 31 additions & 2 deletions lib/config/fileconf.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package config

import (
"bytes"
"crypto/tls"
"encoding/base64"
"fmt"
"io"
Expand Down Expand Up @@ -137,13 +138,28 @@ type SampleFlags struct {
ACMEEnabled bool
// Version is the Teleport Configuration version.
Version string
// PublicAddrs sets the hostport the proxy advertises for the HTTP endpoint.
PublicAddrs []string
// KeyFile is a TLS key file
KeyFile string
// CertFile is a TLS Certificate file
CertFile string
}

// MakeSampleFileConfig returns a sample config to start
// a standalone server
func MakeSampleFileConfig(flags SampleFlags) (fc *FileConfig, err error) {
if flags.ACMEEnabled && flags.ClusterName == "" {
return nil, trace.BadParameter("please provide --cluster-name when using acme, for example --cluster-name=example.com")
if (flags.KeyFile == "") != (flags.CertFile == "") { // xor
return nil, trace.BadParameter("please provide both --key-file and --cert-file")
}

if flags.ACMEEnabled {
if flags.ClusterName == "" {
return nil, trace.BadParameter("please provide --cluster-name when using ACME, for example --cluster-name=example.com")
}
if flags.CertFile != "" {
return nil, trace.BadParameter("could not use --key-file/--cert-file when ACME is enabled")
}
}

conf := service.MakeDefaultConfig()
Expand Down Expand Up @@ -196,6 +212,19 @@ func MakeSampleFileConfig(flags SampleFlags) (fc *FileConfig, err error) {
p.PublicAddr = apiutils.Strings{net.JoinHostPort(flags.ClusterName, fmt.Sprintf("%d", teleport.StandardHTTPSPort))}
p.WebAddr = net.JoinHostPort(defaults.BindIP, fmt.Sprintf("%d", teleport.StandardHTTPSPort))
}
if len(flags.PublicAddrs) > 0 {
p.PublicAddr = apiutils.Strings(flags.PublicAddrs)
}
if flags.KeyFile != "" && flags.CertFile != "" {
if _, err := tls.LoadX509KeyPair(flags.CertFile, flags.KeyFile); err != nil {
return nil, trace.Wrap(err, "failed to load x509 key pair from --key-file and --cert-file")
}

p.KeyPairs = append(p.KeyPairs, KeyPair{
PrivateKey: flags.KeyFile,
Certificate: flags.CertFile,
})
}

fc = &FileConfig{
Version: flags.Version,
Expand Down
17 changes: 17 additions & 0 deletions tool/teleport/common/teleport.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ func Run(options Options) (app *kingpin.Application, executedCommand string, con
"Email to receive updates from Letsencrypt.org.").StringVar(&dumpFlags.ACMEEmail)
dump.Flag("test", "Path to a configuration file to test.").ExistingFileVar(&dumpFlags.testConfigFile)
dump.Flag("version", "Teleport configuration version.").Default(defaults.TeleportConfigVersionV2).StringVar(&dumpFlags.Version)
dump.Flag("public-addr", "A list of public addresses that the proxy advertises for the HTTP endpoint.").StringsVar(&dumpFlags.PublicAddrs)
dump.Flag("cert-file", "Path to a TLS certificate file for the proxy.").ExistingFileVar(&dumpFlags.CertFile)
dump.Flag("key-file", "Path to a TLS key file for the proxy.").ExistingFileVar(&dumpFlags.KeyFile)

// parse CLI commands+flags:
command, err := app.Parse(options.Args)
Expand Down Expand Up @@ -366,6 +369,20 @@ func onConfigDump(flags dumpFlags) error {
flags.LicensePath = filepath.Join(defaults.DataDir, "license.pem")
}

if flags.KeyFile != "" && !filepath.IsAbs(flags.KeyFile) {
flags.KeyFile, err = filepath.Abs(flags.KeyFile)
if err != nil {
return trace.BadParameter("could not find absolute path for --key-file %q", flags.KeyFile)
}
}

if flags.CertFile != "" && !filepath.IsAbs(flags.CertFile) {
flags.CertFile, err = filepath.Abs(flags.CertFile)
if err != nil {
return trace.BadParameter("could not find absolute path for --cert-file %q", flags.CertFile)
}
}

sfc, err := config.MakeSampleFileConfig(flags.SampleFlags)
if err != nil {
return trace.Wrap(err)
Expand Down

0 comments on commit 778168d

Please sign in to comment.