AUTH-2167: Adds CLI option for host key directory
This commit is contained in:
parent
6322c5029d
commit
28cc1c65af
|
@ -74,6 +74,9 @@ const (
|
||||||
// s3URLFlag is the S3 URL of SSH log uploader (e.g. don't use AWS s3 and use google storage bucket instead)
|
// s3URLFlag is the S3 URL of SSH log uploader (e.g. don't use AWS s3 and use google storage bucket instead)
|
||||||
s3URLFlag = "s3-url-host"
|
s3URLFlag = "s3-url-host"
|
||||||
|
|
||||||
|
// hostKeyPath is the path of the dir to save SSH host keys too
|
||||||
|
hostKeyPath = "host-key-path"
|
||||||
|
|
||||||
noIntentMsg = "The --intent argument is required. Cloudflared looks up an Intent to determine what configuration to use (i.e. which tunnels to start). If you don't have any Intents yet, you can use a placeholder Intent Label for now. Then, when you make an Intent with that label, cloudflared will get notified and open the tunnels you specified in that Intent."
|
noIntentMsg = "The --intent argument is required. Cloudflared looks up an Intent to determine what configuration to use (i.e. which tunnels to start). If you don't have any Intents yet, you can use a placeholder Intent Label for now. Then, when you make an Intent with that label, cloudflared will get notified and open the tunnels you specified in that Intent."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -396,7 +399,7 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
|
||||||
}
|
}
|
||||||
|
|
||||||
localServerAddress := "127.0.0.1:" + c.String(sshPortFlag)
|
localServerAddress := "127.0.0.1:" + c.String(sshPortFlag)
|
||||||
server, err := sshserver.New(logManager, logger, version, localServerAddress, c.String("hostname"), shutdownC, c.Duration(sshIdleTimeoutFlag), c.Duration(sshMaxTimeoutFlag))
|
server, err := sshserver.New(logManager, logger, version, localServerAddress, c.String("hostname"), c.Path(hostKeyPath), shutdownC, c.Duration(sshIdleTimeoutFlag), c.Duration(sshMaxTimeoutFlag))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := "Cannot create new SSH Server"
|
msg := "Cannot create new SSH Server"
|
||||||
logger.WithError(err).Error(msg)
|
logger.WithError(err).Error(msg)
|
||||||
|
@ -1019,5 +1022,12 @@ func tunnelFlags(shouldHide bool) []cli.Flag {
|
||||||
EnvVars: []string{"S3_URL"},
|
EnvVars: []string{"S3_URL"},
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
}),
|
}),
|
||||||
|
altsrc.NewPathFlag(&cli.PathFlag{
|
||||||
|
Name: hostKeyPath,
|
||||||
|
Usage: "Absolute path of directory to save SSH host keys in",
|
||||||
|
EnvVars: []string{"HOST_KEY_PATH"},
|
||||||
|
Hidden: true,
|
||||||
|
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,47 +19,44 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
systemConfigPath = "/usr/local/etc/cloudflared/"
|
rsaFilename = "ssh_host_rsa_key"
|
||||||
rsaFilename = "ssh_host_rsa_key"
|
ecdsaFilename = "ssh_host_ecdsa_key"
|
||||||
ecdsaFilename = "ssh_host_ecdsa_key"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *SSHProxy) configureHostKeys() error {
|
var defaultHostKeyDir = filepath.Join(".cloudflared", "host_keys")
|
||||||
if _, err := os.Stat(systemConfigPath); os.IsNotExist(err) {
|
|
||||||
if err := os.MkdirAll(systemConfigPath, 0755); err != nil {
|
func (s *SSHProxy) configureHostKeys(hostKeyDir string) error {
|
||||||
return errors.Wrap(err, fmt.Sprintf("Error creating %s directory", systemConfigPath))
|
if hostKeyDir == "" {
|
||||||
|
homeDir, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hostKeyDir = filepath.Join(homeDir, defaultHostKeyDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat(hostKeyDir); os.IsNotExist(err) {
|
||||||
|
if err := os.MkdirAll(hostKeyDir, 0755); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("Error creating %s directory", hostKeyDir))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.configureHostKey(s.ensureECDSAKeyExists); err != nil {
|
if err := s.configureECDSAKey(hostKeyDir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.configureHostKey(s.ensureRSAKeyExists); err != nil {
|
if err := s.configureRSAKey(hostKeyDir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSHProxy) configureHostKey(keyFunc func() (string, error)) error {
|
func (s *SSHProxy) configureRSAKey(basePath string) error {
|
||||||
path, err := keyFunc()
|
keyPath := filepath.Join(basePath, rsaFilename)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.SetOption(ssh.HostKeyFile(path)); err != nil {
|
|
||||||
return errors.Wrap(err, "Could not set SSH host key")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SSHProxy) ensureRSAKeyExists() (string, error) {
|
|
||||||
keyPath := filepath.Join(systemConfigPath, rsaFilename)
|
|
||||||
if _, err := os.Stat(keyPath); os.IsNotExist(err) {
|
if _, err := os.Stat(keyPath); os.IsNotExist(err) {
|
||||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrap(err, "Error generating RSA host key")
|
return errors.Wrap(err, "Error generating RSA host key")
|
||||||
}
|
}
|
||||||
|
|
||||||
privateKey := &pem.Block{
|
privateKey := &pem.Block{
|
||||||
|
@ -68,25 +65,28 @@ func (s *SSHProxy) ensureRSAKeyExists() (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = writePrivateKey(keyPath, privateKey); err != nil {
|
if err = writePrivateKey(keyPath, privateKey); err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.logger.Debug("Created new RSA SSH host key: ", keyPath)
|
s.logger.Debug("Created new RSA SSH host key: ", keyPath)
|
||||||
}
|
}
|
||||||
return keyPath, nil
|
if err := s.SetOption(ssh.HostKeyFile(keyPath)); err != nil {
|
||||||
|
return errors.Wrap(err, "Could not set SSH RSA host key")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSHProxy) ensureECDSAKeyExists() (string, error) {
|
func (s *SSHProxy) configureECDSAKey(basePath string) error {
|
||||||
keyPath := filepath.Join(systemConfigPath, ecdsaFilename)
|
keyPath := filepath.Join(basePath, ecdsaFilename)
|
||||||
if _, err := os.Stat(keyPath); os.IsNotExist(err) {
|
if _, err := os.Stat(keyPath); os.IsNotExist(err) {
|
||||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrap(err, "Error generating ECDSA host key")
|
return errors.Wrap(err, "Error generating ECDSA host key")
|
||||||
}
|
}
|
||||||
|
|
||||||
keyBytes, err := x509.MarshalECPrivateKey(key)
|
keyBytes, err := x509.MarshalECPrivateKey(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrap(err, "Error marshalling ECDSA key")
|
return errors.Wrap(err, "Error marshalling ECDSA key")
|
||||||
}
|
}
|
||||||
|
|
||||||
privateKey := &pem.Block{
|
privateKey := &pem.Block{
|
||||||
|
@ -95,12 +95,15 @@ func (s *SSHProxy) ensureECDSAKeyExists() (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = writePrivateKey(keyPath, privateKey); err != nil {
|
if err = writePrivateKey(keyPath, privateKey); err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.logger.Debug("Created new ECDSA SSH host key: ", keyPath)
|
s.logger.Debug("Created new ECDSA SSH host key: ", keyPath)
|
||||||
}
|
}
|
||||||
return keyPath, nil
|
if err := s.SetOption(ssh.HostKeyFile(keyPath)); err != nil {
|
||||||
|
return errors.Wrap(err, "Could not set SSH ECDSA host key")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writePrivateKey(keyPath string, privateKey *pem.Block) error {
|
func writePrivateKey(keyPath string, privateKey *pem.Block) error {
|
||||||
|
|
|
@ -78,7 +78,7 @@ type SSHPreamble struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new SSHProxy and configures its host keys and authentication by the data provided
|
// New creates a new SSHProxy and configures its host keys and authentication by the data provided
|
||||||
func New(logManager sshlog.Manager, logger *logrus.Logger, version, localAddress, hostname string, shutdownC chan struct{}, idleTimeout, maxTimeout time.Duration) (*SSHProxy, error) {
|
func New(logManager sshlog.Manager, logger *logrus.Logger, version, localAddress, hostname, hostKeyDir string, shutdownC chan struct{}, idleTimeout, maxTimeout time.Duration) (*SSHProxy, error) {
|
||||||
sshProxy := SSHProxy{
|
sshProxy := SSHProxy{
|
||||||
hostname: hostname,
|
hostname: hostname,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
@ -98,7 +98,7 @@ func New(logManager sshlog.Manager, logger *logrus.Logger, version, localAddress
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sshProxy.configureHostKeys(); err != nil {
|
if err := sshProxy.configureHostKeys(hostKeyDir); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ type SSHPreamble struct {
|
||||||
JWT string
|
JWT string
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(_ sshlog.Manager, _ *logrus.Logger, _, _, _ string, _ chan struct{}, _, _ time.Duration) (*SSHServer, error) {
|
func New(_ sshlog.Manager, _ *logrus.Logger, _, _, _, _ string, _ chan struct{}, _, _ time.Duration) (*SSHServer, error) {
|
||||||
return nil, errors.New("cloudflared ssh server is not supported on windows")
|
return nil, errors.New("cloudflared ssh server is not supported on windows")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue