Skip to content

Commit 5043554

Browse files
committed
TUN-4118: Don't overwrite existing file with tunnel credentials. For ad-hoc tunnels, this means tunnel won't start if there's a file in the way.
1 parent 9018ee5 commit 5043554

File tree

3 files changed

+32
-24
lines changed

3 files changed

+32
-24
lines changed

CHANGES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313
### Improvements
1414

15-
- none
15+
- Tunnel create command, as well as, running ad-hoc tunnels using `cloudflared tunnel -name NAME`, will not overwrite
16+
existing files when writing tunnel credentials.
1617

1718
### Bug Fixes
1819

cmd/cloudflared/tunnel/subcommand_context.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"fmt"
66
"os"
7+
"path/filepath"
78
"strings"
89

910
"github.com/google/uuid"
@@ -147,7 +148,7 @@ func (sc *subcommandContext) readTunnelCredentials(credFinder CredFinder) (conne
147148
return credentials, nil
148149
}
149150

150-
func (sc *subcommandContext) create(name string, credentialsOutputPath string) (*tunnelstore.Tunnel, error) {
151+
func (sc *subcommandContext) create(name string, credentialsFilePath string) (*tunnelstore.Tunnel, error) {
151152
client, err := sc.client()
152153
if err != nil {
153154
return nil, errors.Wrap(err, "couldn't create client to talk to Argo Tunnel backend")
@@ -173,27 +174,40 @@ func (sc *subcommandContext) create(name string, credentialsOutputPath string) (
173174
TunnelID: tunnel.ID,
174175
TunnelName: name,
175176
}
176-
filePath, writeFileErr := writeTunnelCredentials(credential.certPath, credentialsOutputPath, &tunnelCredentials)
177+
usedCertPath := false
178+
if credentialsFilePath == "" {
179+
originCertDir := filepath.Dir(credential.certPath)
180+
credentialsFilePath, err = tunnelFilePath(tunnelCredentials.TunnelID, originCertDir)
181+
if err != nil {
182+
return nil, err
183+
}
184+
usedCertPath = true
185+
}
186+
writeFileErr := writeTunnelCredentials(credentialsFilePath, &tunnelCredentials)
177187
if writeFileErr != nil {
178188
var errorLines []string
179-
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))
189+
errorLines = append(errorLines, fmt.Sprintf("Your tunnel '%v' was created with ID %v. However, cloudflared couldn't write tunnel credentials to %s.", tunnel.Name, tunnel.ID, credentialsFilePath))
180190
errorLines = append(errorLines, fmt.Sprintf("The file-writing error is: %v", writeFileErr))
181191
if deleteErr := client.DeleteTunnel(tunnel.ID); deleteErr != nil {
182192
errorLines = append(errorLines, fmt.Sprintf("Cloudflared tried to delete the tunnel for you, but encountered an error. You should use `cloudflared tunnel delete %v` to delete the tunnel yourself, because the tunnel can't be run without the tunnelfile.", tunnel.ID))
183193
errorLines = append(errorLines, fmt.Sprintf("The delete tunnel error is: %v", deleteErr))
184194
} else {
185-
errorLines = append(errorLines, fmt.Sprintf("The tunnel was deleted, because the tunnel can't be run without the tunnelfile"))
195+
errorLines = append(errorLines, fmt.Sprintf("The tunnel was deleted, because the tunnel can't be run without the credentials file"))
186196
}
187197
errorMsg := strings.Join(errorLines, "\n")
188198
return nil, errors.New(errorMsg)
189199
}
190-
sc.log.Info().Msgf("Tunnel credentials written to %v. cloudflared chose this file based on where your origin certificate was found. Keep this file secret. To revoke these credentials, delete the tunnel.", filePath)
191200

192201
if outputFormat := sc.c.String(outputFormatFlag.Name); outputFormat != "" {
193202
return nil, renderOutput(outputFormat, &tunnel)
194203
}
195204

196-
sc.log.Info().Msgf("Created tunnel %s with id %s", tunnel.Name, tunnel.ID)
205+
fmt.Printf("Tunnel credentials written to %v.", credentialsFilePath)
206+
if usedCertPath {
207+
fmt.Print(" cloudflared chose this file based on where your origin certificate was found.")
208+
}
209+
fmt.Println(" Keep this file secret. To revoke these credentials, delete the tunnel.")
210+
fmt.Printf("\nCreated tunnel %s with id %s\n", tunnel.Name, tunnel.ID)
197211
return tunnel, nil
198212
}
199213

cmd/cloudflared/tunnel/subcommands.go

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -183,27 +183,20 @@ func tunnelFilePath(tunnelID uuid.UUID, directory string) (string, error) {
183183
return homedir.Expand(filePath)
184184
}
185185

186-
// If an `outputFile` is given, write the credentials there.
187-
// Otherwise, write it to the same directory as the originCert,
188-
// with the filename `<tunnel id>.json`.
189-
func writeTunnelCredentials(
190-
originCertPath, outputFile string,
191-
credentials *connection.Credentials,
192-
) (filePath string, err error) {
193-
filePath = outputFile
194-
if outputFile == "" {
195-
originCertDir := filepath.Dir(originCertPath)
196-
filePath, err = tunnelFilePath(credentials.TunnelID, originCertDir)
197-
}
198-
if err != nil {
199-
return "", err
186+
// writeTunnelCredentials saves `credentials` as a JSON into `filePath`, only if
187+
// the file does not exist already
188+
func writeTunnelCredentials(filePath string, credentials *connection.Credentials) error {
189+
if _, err := os.Stat(filePath); !os.IsNotExist(err) {
190+
if err == nil {
191+
return fmt.Errorf("%s already exists", filePath)
192+
}
193+
return err
200194
}
201-
// Write the name and ID to the file too
202195
body, err := json.Marshal(credentials)
203196
if err != nil {
204-
return "", errors.Wrap(err, "Unable to marshal tunnel credentials to JSON")
197+
return errors.Wrap(err, "Unable to marshal tunnel credentials to JSON")
205198
}
206-
return filePath, ioutil.WriteFile(filePath, body, 400)
199+
return ioutil.WriteFile(filePath, body, 400)
207200
}
208201

209202
func buildListCommand() *cli.Command {

0 commit comments

Comments
 (0)