TUN-3131: Allow user to specify tunnel credentials path, and remove it in tunnel delete command
This commit is contained in:
parent
1ed9e0fceb
commit
87e06100df
|
@ -12,18 +12,24 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
"gopkg.in/urfave/cli.v2"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
"github.com/cloudflare/cloudflared/certutil"
|
"github.com/cloudflare/cloudflared/certutil"
|
||||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
||||||
|
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
|
||||||
"github.com/cloudflare/cloudflared/logger"
|
"github.com/cloudflare/cloudflared/logger"
|
||||||
"github.com/cloudflare/cloudflared/origin"
|
"github.com/cloudflare/cloudflared/origin"
|
||||||
"github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
"github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||||
"github.com/cloudflare/cloudflared/tunnelstore"
|
"github.com/cloudflare/cloudflared/tunnelstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
credFileFlagAlias = "cred-file"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
showDeletedFlag = &cli.BoolFlag{
|
showDeletedFlag = &cli.BoolFlag{
|
||||||
Name: "show-deleted",
|
Name: "show-deleted",
|
||||||
|
@ -43,6 +49,11 @@ var (
|
||||||
"overwrite the previous tunnel. If you want to use a single hostname with multiple " +
|
"overwrite the previous tunnel. If you want to use a single hostname with multiple " +
|
||||||
"tunnels, you can do so with Cloudflare's Load Balancer product.",
|
"tunnels, you can do so with Cloudflare's Load Balancer product.",
|
||||||
}
|
}
|
||||||
|
credentialsFileFlag = &cli.StringFlag{
|
||||||
|
Name: "credentials-file",
|
||||||
|
Aliases: []string{credFileFlagAlias},
|
||||||
|
Usage: "File path of tunnel credentials",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const hideSubcommands = true
|
const hideSubcommands = true
|
||||||
|
@ -118,13 +129,15 @@ func createTunnel(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tunnelFilePath(tunnelID, originCertPath string) (string, error) {
|
func tunnelFilePath(tunnelID, directory string) (string, error) {
|
||||||
fileName := fmt.Sprintf("%v.json", tunnelID)
|
fileName := fmt.Sprintf("%v.json", tunnelID)
|
||||||
return filepath.Clean(fmt.Sprintf("%v/../%v", originCertPath, fileName)), nil
|
filePath := filepath.Clean(fmt.Sprintf("%s/%s", directory, fileName))
|
||||||
|
return homedir.Expand(filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeTunnelCredentials(tunnelID, accountID, originCertPath string, tunnelSecret []byte, logger logger.Service) error {
|
func writeTunnelCredentials(tunnelID, accountID, originCertPath string, tunnelSecret []byte, logger logger.Service) error {
|
||||||
filePath, err := tunnelFilePath(tunnelID, originCertPath)
|
originCertDir := filepath.Dir(originCertPath)
|
||||||
|
filePath, err := tunnelFilePath(tunnelID, originCertDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -140,8 +153,8 @@ func writeTunnelCredentials(tunnelID, accountID, originCertPath string, tunnelSe
|
||||||
return ioutil.WriteFile(filePath, body, 400)
|
return ioutil.WriteFile(filePath, body, 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readTunnelCredentials(tunnelID, originCertPath string) (*pogs.TunnelAuth, error) {
|
func readTunnelCredentials(c *cli.Context, tunnelID string, logger logger.Service) (*pogs.TunnelAuth, error) {
|
||||||
filePath, err := tunnelFilePath(tunnelID, originCertPath)
|
filePath, err := tunnelCredentialsPath(c, tunnelID, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -157,6 +170,42 @@ func readTunnelCredentials(tunnelID, originCertPath string) (*pogs.TunnelAuth, e
|
||||||
return &auth, nil
|
return &auth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tunnelCredentialsPath(c *cli.Context, tunnelID string, logger logger.Service) (string, error) {
|
||||||
|
if filePath := c.String("credentials-file"); filePath != "" {
|
||||||
|
if validFilePath(filePath) {
|
||||||
|
return filePath, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to look for tunnel credentials in the origin cert directory
|
||||||
|
if originCertPath, err := findOriginCert(c, logger); err == nil {
|
||||||
|
originCertDir := filepath.Dir(originCertPath)
|
||||||
|
if filePath, err := tunnelFilePath(tunnelID, originCertDir); err == nil {
|
||||||
|
if validFilePath(filePath) {
|
||||||
|
return filePath, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last resort look under default config directories
|
||||||
|
for _, configDir := range config.DefaultConfigDirs {
|
||||||
|
if filePath, err := tunnelFilePath(tunnelID, configDir); err == nil {
|
||||||
|
if validFilePath(filePath) {
|
||||||
|
return filePath, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("Tunnel credentials file not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func validFilePath(path string) bool {
|
||||||
|
fileStat, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return !fileStat.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
func buildListCommand() *cli.Command {
|
func buildListCommand() *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
|
@ -246,6 +295,7 @@ func buildDeleteCommand() *cli.Command {
|
||||||
Usage: "Delete existing tunnel with given ID",
|
Usage: "Delete existing tunnel with given ID",
|
||||||
ArgsUsage: "TUNNEL-ID",
|
ArgsUsage: "TUNNEL-ID",
|
||||||
Hidden: hideSubcommands,
|
Hidden: hideSubcommands,
|
||||||
|
Flags: []cli.Flag{credentialsFileFlag},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +324,16 @@ func deleteTunnel(c *cli.Context) error {
|
||||||
return errors.Wrapf(err, "Error deleting tunnel %s", id)
|
return errors.Wrapf(err, "Error deleting tunnel %s", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tunnelCredentialsPath, err := tunnelCredentialsPath(c, id, logger)
|
||||||
|
if err != nil {
|
||||||
|
logger.Infof("Cannot locate tunnel credentials to delete, error: %v. Please delete the file manually", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.Remove(tunnelCredentialsPath); err != nil {
|
||||||
|
logger.Infof("Cannot delete tunnel credentials, error: %v. Please delete the file manually", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +380,7 @@ func buildRunCommand() *cli.Command {
|
||||||
Usage: "Proxy a local web server by running the given tunnel",
|
Usage: "Proxy a local web server by running the given tunnel",
|
||||||
ArgsUsage: "TUNNEL-ID",
|
ArgsUsage: "TUNNEL-ID",
|
||||||
Hidden: hideSubcommands,
|
Hidden: hideSubcommands,
|
||||||
Flags: []cli.Flag{forceFlag},
|
Flags: []cli.Flag{forceFlag, credentialsFileFlag},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,11 +399,7 @@ func runTunnel(c *cli.Context) error {
|
||||||
return errors.Wrap(err, "error setting up logger")
|
return errors.Wrap(err, "error setting up logger")
|
||||||
}
|
}
|
||||||
|
|
||||||
originCertPath, err := findOriginCert(c, logger)
|
credentials, err := readTunnelCredentials(c, id, logger)
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "Error locating origin cert")
|
|
||||||
}
|
|
||||||
credentials, err := readTunnelCredentials(id, originCertPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package tunnel
|
package tunnel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/cloudflare/cloudflared/tunnelstore"
|
"github.com/cloudflare/cloudflared/tunnelstore"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -72,8 +75,11 @@ func Test_fmtConnections(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTunnelfilePath(t *testing.T) {
|
func TestTunnelfilePath(t *testing.T) {
|
||||||
actual, err := tunnelFilePath("tunnel", "~/.cloudflared/cert.pem")
|
originCertDir := filepath.Dir("~/.cloudflared/cert.pem")
|
||||||
|
actual, err := tunnelFilePath("tunnel", originCertDir)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
expected := "~/.cloudflared/tunnel.json"
|
homeDir, err := homedir.Dir()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
expected := fmt.Sprintf("%s/.cloudflared/tunnel.json", homeDir)
|
||||||
assert.Equal(t, expected, actual)
|
assert.Equal(t, expected, actual)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue