diff --git a/cmd/cloudflared/tunnel/cmd.go b/cmd/cloudflared/tunnel/cmd.go index a9e09f29..a600cb70 100644 --- a/cmd/cloudflared/tunnel/cmd.go +++ b/cmd/cloudflared/tunnel/cmd.go @@ -154,7 +154,7 @@ func TunnelCommand(c *cli.Context) error { return err } if name := c.String("name"); name != "" { // Start a named tunnel - return runAdhocNamedTunnel(sc, name) + return runAdhocNamedTunnel(sc, name, c.String(CredFileFlag)) } if ref := config.GetConfiguration().TunnelID; ref != "" { return fmt.Errorf("Use `cloudflared tunnel run` to start tunnel %s", ref) @@ -169,10 +169,10 @@ func Init(ver string, gracefulShutdown chan struct{}) { } // runAdhocNamedTunnel create, route and run a named tunnel in one command -func runAdhocNamedTunnel(sc *subcommandContext, name string) error { +func runAdhocNamedTunnel(sc *subcommandContext, name, credentialsOutputPath string) error { tunnel, ok, err := sc.tunnelActive(name) if err != nil || !ok { - tunnel, err = sc.create(name) + tunnel, err = sc.create(name, credentialsOutputPath) if err != nil { return errors.Wrap(err, "failed to create tunnel") } @@ -539,6 +539,7 @@ func tunnelFlags(shouldHide bool) []cli.Flag { flags = append(flags, configureLoggingFlags(shouldHide)...) flags = append(flags, configureProxyDNSFlags(shouldHide)...) flags = append(flags, []cli.Flag{ + credentialsFileFlag, altsrc.NewBoolFlag(&cli.BoolFlag{ Name: "is-autoupdated", Usage: "Signal the new process that Argo Tunnel client has been autoupdated", diff --git a/cmd/cloudflared/tunnel/subcommand_context.go b/cmd/cloudflared/tunnel/subcommand_context.go index 056d5644..d7a8a9d9 100644 --- a/cmd/cloudflared/tunnel/subcommand_context.go +++ b/cmd/cloudflared/tunnel/subcommand_context.go @@ -147,7 +147,7 @@ func (sc *subcommandContext) readTunnelCredentials(credFinder CredFinder) (conne return credentials, nil } -func (sc *subcommandContext) create(name string) (*tunnelstore.Tunnel, error) { +func (sc *subcommandContext) create(name string, credentialsOutputPath string) (*tunnelstore.Tunnel, error) { client, err := sc.client() if err != nil { return nil, errors.Wrap(err, "couldn't create client to talk to Argo Tunnel backend") @@ -173,7 +173,7 @@ func (sc *subcommandContext) create(name string) (*tunnelstore.Tunnel, error) { TunnelID: tunnel.ID, TunnelName: name, } - filePath, writeFileErr := writeTunnelCredentials(credential.certPath, &tunnelCredentials) + filePath, writeFileErr := writeTunnelCredentials(credential.certPath, credentialsOutputPath, &tunnelCredentials) if writeFileErr != nil { var errorLines []string errorLines = append(errorLines, fmt.Sprintf("Your tunnel '%v' was created with ID %v. However, cloudflared couldn't write to the tunnel credentials file at %v.json.", tunnel.Name, tunnel.ID, tunnel.ID)) diff --git a/cmd/cloudflared/tunnel/subcommands.go b/cmd/cloudflared/tunnel/subcommands.go index 92f93ac0..62b3fced 100644 --- a/cmd/cloudflared/tunnel/subcommands.go +++ b/cmd/cloudflared/tunnel/subcommands.go @@ -90,7 +90,7 @@ var ( credentialsFileFlag = altsrc.NewStringFlag(&cli.StringFlag{ Name: CredFileFlag, Aliases: []string{CredFileFlagAlias}, - Usage: "File path of tunnel credentials", + Usage: "Filepath at which to read/write the tunnel credentials", EnvVars: []string{"TUNNEL_CRED_FILE"}, }) forceDeleteFlag = &cli.BoolFlag{ @@ -121,7 +121,7 @@ func buildCreateCommand() *cli.Command { For example, to create a tunnel named 'my-tunnel' run: $ cloudflared tunnel create my-tunnel`, - Flags: []cli.Flag{outputFormatFlag}, + Flags: []cli.Flag{outputFormatFlag, credentialsFileFlag}, CustomHelpTemplate: commandHelpTemplate(), } } @@ -144,7 +144,7 @@ func createCommand(c *cli.Context) error { } name := c.Args().First() - _, err = sc.create(name) + _, err = sc.create(name, c.String(CredFileFlag)) return errors.Wrap(err, "failed to create tunnel") } @@ -154,12 +154,18 @@ func tunnelFilePath(tunnelID uuid.UUID, directory string) (string, error) { return homedir.Expand(filePath) } +// If an `outputFile` is given, write the credentials there. +// Otherwise, write it to the same directory as the originCert, +// with the filename `.json`. func writeTunnelCredentials( - originCertPath string, + originCertPath, outputFile string, credentials *connection.Credentials, ) (filePath string, err error) { - originCertDir := filepath.Dir(originCertPath) - filePath, err = tunnelFilePath(credentials.TunnelID, originCertDir) + filePath = outputFile + if outputFile == "" { + originCertDir := filepath.Dir(originCertPath) + filePath, err = tunnelFilePath(credentials.TunnelID, originCertDir) + } if err != nil { return "", err }