mirror of
https://github.com/fumiama/terasu-cloudflared.git
synced 2026-06-05 00:50:24 +08:00
## Summary Within the scope of the FEDRamp High RM, it is necessary to detect if an user should connect to a FEDRamp colo. At first, it was considered to add the --fedramp as global flag however this could be a footgun for the user or even an hindrance, thus, the proposal is to save in the token (during login) if the user authenticated using the FEDRamp Dashboard. This solution makes it easier to the user as they will only be required to pass the flag in login and nothing else. * Introduces the new field, endpoint, in OriginCert * Refactors login to remove the private key and certificate which are no longer used * Login will only store the Argo Tunnel Token * Remove namedTunnelToken as it was only used to for serialization Closes TUN-8960
155 lines
4.0 KiB
Go
155 lines
4.0 KiB
Go
package tunnel
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
homedir "github.com/mitchellh/go-homedir"
|
|
"github.com/pkg/errors"
|
|
"github.com/urfave/cli/v2"
|
|
|
|
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
|
"github.com/cloudflare/cloudflared/config"
|
|
"github.com/cloudflare/cloudflared/credentials"
|
|
"github.com/cloudflare/cloudflared/logger"
|
|
"github.com/cloudflare/cloudflared/token"
|
|
)
|
|
|
|
const (
|
|
baseLoginURL = "https://dash.cloudflare.com/argotunnel"
|
|
callbackURL = "https://login.cloudflareaccess.org/"
|
|
// For now these are the same but will change in the future once we know which URLs to use (TUN-8872)
|
|
fedBaseLoginURL = "https://dash.cloudflare.com/argotunnel"
|
|
fedCallbackStoreURL = "https://login.cloudflareaccess.org/"
|
|
fedRAMPParamName = "fedramp"
|
|
loginURLParamName = "loginURL"
|
|
callbackURLParamName = "callbackURL"
|
|
)
|
|
|
|
var (
|
|
loginURL = &cli.StringFlag{
|
|
Name: loginURLParamName,
|
|
Value: baseLoginURL,
|
|
Usage: "The URL used to login (default is https://dash.cloudflare.com/argotunnel)",
|
|
}
|
|
callbackStore = &cli.StringFlag{
|
|
Name: callbackURLParamName,
|
|
Value: callbackURL,
|
|
Usage: "The URL used for the callback (default is https://login.cloudflareaccess.org/)",
|
|
}
|
|
fedramp = &cli.BoolFlag{
|
|
Name: fedRAMPParamName,
|
|
Aliases: []string{"f"},
|
|
Usage: "Login with FedRAMP High environment.",
|
|
}
|
|
)
|
|
|
|
func buildLoginSubcommand(hidden bool) *cli.Command {
|
|
return &cli.Command{
|
|
Name: "login",
|
|
Action: cliutil.ConfiguredAction(login),
|
|
Usage: "Generate a configuration file with your login details",
|
|
ArgsUsage: " ",
|
|
Hidden: hidden,
|
|
Flags: []cli.Flag{
|
|
loginURL,
|
|
callbackStore,
|
|
fedramp,
|
|
},
|
|
}
|
|
}
|
|
|
|
func login(c *cli.Context) error {
|
|
log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog)
|
|
|
|
path, ok, err := checkForExistingCert()
|
|
if ok {
|
|
log.Error().Err(err).Msgf("You have an existing certificate at %s which login would overwrite.\nIf this is intentional, please move or delete that file then run this command again.\n", path)
|
|
return nil
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
|
|
var (
|
|
baseloginURL = c.String(loginURLParamName)
|
|
callbackStoreURL = c.String(callbackURLParamName)
|
|
)
|
|
|
|
isFEDRamp := c.Bool(fedRAMPParamName)
|
|
if isFEDRamp {
|
|
baseloginURL = fedBaseLoginURL
|
|
callbackStoreURL = fedCallbackStoreURL
|
|
}
|
|
|
|
loginURL, err := url.Parse(baseloginURL)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resourceData, err := token.RunTransfer(
|
|
loginURL,
|
|
"",
|
|
"cert",
|
|
"callback",
|
|
callbackStoreURL,
|
|
false,
|
|
false,
|
|
log,
|
|
)
|
|
if err != nil {
|
|
log.Error().Err(err).Msgf("Failed to write the certificate.\n\nYour browser will download the certificate instead. You will have to manually\ncopy it to the following path:\n\n%s\n", path)
|
|
return err
|
|
}
|
|
|
|
cert, err := credentials.DecodeOriginCert(resourceData)
|
|
if err != nil {
|
|
log.Error().Err(err).Msg("failed to decode origin certificate")
|
|
return err
|
|
}
|
|
|
|
if isFEDRamp {
|
|
cert.Endpoint = credentials.FedEndpoint
|
|
}
|
|
|
|
resourceData, err = cert.EncodeOriginCert()
|
|
if err != nil {
|
|
log.Error().Err(err).Msg("failed to encode origin certificate")
|
|
return err
|
|
}
|
|
|
|
if err := os.WriteFile(path, resourceData, 0600); err != nil {
|
|
return errors.Wrap(err, fmt.Sprintf("error writing cert to %s", path))
|
|
}
|
|
|
|
log.Info().Msgf("You have successfully logged in.\nIf you wish to copy your credentials to a server, they have been saved to:\n%s\n", path)
|
|
return nil
|
|
}
|
|
|
|
func checkForExistingCert() (string, bool, error) {
|
|
configPath, err := homedir.Expand(config.DefaultConfigSearchDirectories()[0])
|
|
if err != nil {
|
|
return "", false, err
|
|
}
|
|
ok, err := config.FileExists(configPath)
|
|
if !ok && err == nil {
|
|
// create config directory if doesn't already exist
|
|
err = os.Mkdir(configPath, 0700)
|
|
}
|
|
if err != nil {
|
|
return "", false, err
|
|
}
|
|
path := filepath.Join(configPath, credentials.DefaultCredentialFile)
|
|
fileInfo, err := os.Stat(path)
|
|
if err == nil && fileInfo.Size() > 0 {
|
|
return path, true, nil
|
|
}
|
|
if err != nil && err.(*os.PathError).Err != syscall.ENOENT {
|
|
return path, false, err
|
|
}
|
|
|
|
return path, false, nil
|
|
}
|