diff --git a/internal/rest/mgmt/helpers.go b/internal/rest/mgmt/helpers.go index a54805eeb..006a0871b 100644 --- a/internal/rest/mgmt/helpers.go +++ b/internal/rest/mgmt/helpers.go @@ -17,12 +17,20 @@ package mgmt import ( "context" + "crypto/tls" + "crypto/x509" + "errors" "github.com/openziti/edge-api/rest_management_api_client" + rest_mgmt "github.com/openziti/edge-api/rest_management_api_client/current_api_session" "github.com/openziti/edge-api/rest_management_api_client/identity" "github.com/openziti/edge-api/rest_management_api_client/service" "github.com/openziti/edge-api/rest_management_api_client/service_policy" "github.com/openziti/edge-api/rest_model" + "github.com/openziti/edge-api/rest_util" + "github.com/openziti/ziti/ziti/util" log "github.com/sirupsen/logrus" + "net/http" + "os" "time" ) @@ -80,4 +88,53 @@ func ServicePolicyFromFilter(client *rest_management_api_client.ZitiEdgeManageme func NameFilter(name string) string { return `name="` + name + `"` +} + +func NewClient() (*rest_management_api_client.ZitiEdgeManagement, error) { + cachedCreds, _, loadErr := util.LoadRestClientConfig() + if loadErr != nil { + return nil, loadErr + } + + cachedId := cachedCreds.EdgeIdentities[cachedCreds.Default] //only support default for now + if cachedId == nil { + return nil, errors.New("no identity found") + } + + caPool := x509.NewCertPool() + if _, cacertErr := os.Stat(cachedId.CaCert); cacertErr == nil { + rootPemData, err := os.ReadFile(cachedId.CaCert) + if err != nil { + return nil, err + } + caPool.AppendCertsFromPEM(rootPemData) + } else { + return nil, errors.New("CA cert file not found in config file") + } + + tlsConfig := &tls.Config{ + RootCAs: caPool, + } + + transport := &http.Transport{ + TLSClientConfig: tlsConfig, + } + + // Assign the transport to the default HTTP client + http.DefaultClient = &http.Client{ + Transport: transport, + } + c, e := rest_util.NewEdgeManagementClientWithToken(http.DefaultClient, cachedId.Url, cachedId.Token) + if e != nil { + return nil, e + } + + apiSessionParams := &rest_mgmt.GetCurrentAPISessionParams{ + Context: context.Background(), + } + _, authErr := c.CurrentAPISession.GetCurrentAPISession(apiSessionParams, nil) + if authErr != nil { + return nil, errors.New("client not authenticated. login with 'ziti edge login' before executing") + } + return c, nil } \ No newline at end of file diff --git a/ziti/cmd/cmd.go b/ziti/cmd/cmd.go index 0b0608804..dddeaa4f5 100644 --- a/ziti/cmd/cmd.go +++ b/ziti/cmd/cmd.go @@ -143,8 +143,8 @@ func NewCmdRoot(in io.Reader, out, err io.Writer, cmd *cobra.Command) *cobra.Com opsCommands.AddCommand(database.NewCmdDb(out, err)) opsCommands.AddCommand(NewCmdLogFormat(out, err)) opsCommands.AddCommand(NewUnwrapIdentityFileCommand(out, err)) - opsCommands.AddCommand(verify.NewVerifyNetwork()) - opsCommands.AddCommand(verify.NewVerifyTraffic()) + opsCommands.AddCommand(verify.NewVerifyNetwork(out, err)) + opsCommands.AddCommand(verify.NewVerifyTraffic(out, err)) groups := templates.CommandGroups{ { diff --git a/ziti/cmd/edge/login.go b/ziti/cmd/edge/login.go index 636e109b3..3cafe79dd 100644 --- a/ziti/cmd/edge/login.go +++ b/ziti/cmd/edge/login.go @@ -56,6 +56,25 @@ type LoginOptions struct { FileCertCreds *edge_apis.IdentityCredentials } +func AddLoginFlags(cmd *cobra.Command, options *LoginOptions) { + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + + cmd.Flags().StringVarP(&options.Username, "username", "u", "", "username to use for authenticating to the Ziti Edge Controller ") + cmd.Flags().StringVarP(&options.Password, "password", "p", "", "password to use for authenticating to the Ziti Edge Controller, if -u is supplied and -p is not, a value will be prompted for") + cmd.Flags().StringVarP(&options.Token, "token", "t", "", "if an api token has already been acquired, it can be set in the config with this option. This will set the session to read only by default") + cmd.Flags().StringVarP(&options.CaCert, "ca", "", "", "additional root certificates used by the Ziti Edge Controller") + cmd.Flags().BoolVar(&options.ReadOnly, "read-only", false, "marks this login as read-only. Note: this is not a guarantee that nothing can be changed on the server. Care should still be taken!") + cmd.Flags().BoolVarP(&options.Yes, "yes", "y", false, "If set, responds to prompts with yes. This will result in untrusted certs being accepted or updated.") + cmd.Flags().BoolVar(&options.IgnoreConfig, "ignore-config", false, "If set, does not use value from the config file for hostname or username. Values must be entered or will be prompted for.") + cmd.Flags().StringVarP(&options.ClientCert, "client-cert", "c", "", "A certificate used to authenticate") + cmd.Flags().StringVarP(&options.ClientKey, "client-key", "k", "", "The key to use with certificate authentication") + cmd.Flags().StringVarP(&options.ExtJwt, "ext-jwt", "e", "", "A file containing a JWT from an external provider to be used for authentication") + cmd.Flags().StringVarP(&options.File, "file", "f", "", "An identity file to use for authentication") + + options.AddCommonFlags(cmd) +} + // NewLoginCmd creates the command func NewLoginCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &LoginOptions{ @@ -77,23 +96,8 @@ func NewLoginCmd(out io.Writer, errOut io.Writer) *cobra.Command { }, SuggestFor: []string{}, } - - // allow interspersing positional args and flags - cmd.Flags().SetInterspersed(true) - - cmd.Flags().StringVarP(&options.Username, "username", "u", "", "username to use for authenticating to the Ziti Edge Controller ") - cmd.Flags().StringVarP(&options.Password, "password", "p", "", "password to use for authenticating to the Ziti Edge Controller, if -u is supplied and -p is not, a value will be prompted for") - cmd.Flags().StringVarP(&options.Token, "token", "t", "", "if an api token has already been acquired, it can be set in the config with this option. This will set the session to read only by default") - cmd.Flags().StringVarP(&options.CaCert, "ca", "", "", "additional root certificates used by the Ziti Edge Controller") - cmd.Flags().BoolVar(&options.ReadOnly, "read-only", false, "marks this login as read-only. Note: this is not a guarantee that nothing can be changed on the server. Care should still be taken!") - cmd.Flags().BoolVarP(&options.Yes, "yes", "y", false, "If set, responds to prompts with yes. This will result in untrusted certs being accepted or updated.") - cmd.Flags().BoolVar(&options.IgnoreConfig, "ignore-config", false, "If set, does not use value from the config file for hostname or username. Values must be entered or will be prompted for.") - cmd.Flags().StringVarP(&options.ClientCert, "client-cert", "c", "", "A certificate used to authenticate") - cmd.Flags().StringVarP(&options.ClientKey, "client-key", "k", "", "The key to use with certificate authentication") - cmd.Flags().StringVarP(&options.ExtJwt, "ext-jwt", "e", "", "A file containing a JWT from an external provider to be used for authentication") - cmd.Flags().StringVarP(&options.File, "file", "f", "", "An identity file to use for authentication") - - options.AddCommonFlags(cmd) + + AddLoginFlags(cmd, options) return cmd } diff --git a/ziti/cmd/verify/ops_verify_network.go b/ziti/cmd/verify/ops_verify_network.go index e08720f3c..e6599248f 100644 --- a/ziti/cmd/verify/ops_verify_network.go +++ b/ziti/cmd/verify/ops_verify_network.go @@ -17,6 +17,7 @@ package verify import ( "fmt" + "io" "net" "os" "strings" @@ -48,7 +49,7 @@ type stringMapList []interface{} type StringMap map[string]interface{} -func NewVerifyNetwork() *cobra.Command { +func NewVerifyNetwork(_ io.Writer, _ io.Writer) *cobra.Command { n := &network{} cmd := &cobra.Command{ diff --git a/ziti/cmd/verify/ops_verify_traffic.go b/ziti/cmd/verify/ops_verify_traffic.go index ebd376b4c..1bbba8988 100644 --- a/ziti/cmd/verify/ops_verify_traffic.go +++ b/ziti/cmd/verify/ops_verify_traffic.go @@ -18,12 +18,18 @@ package verify import ( "bufio" "context" + "crypto/tls" "crypto/x509" "fmt" "github.com/michaelquigley/pfxlog" + mgmtc "github.com/openziti/edge-api/rest_management_api_client/current_api_session" "github.com/openziti/foundation/v2/term" + "github.com/openziti/ziti/ziti/cmd/edge" + "github.com/openziti/ziti/ziti/util" "github.com/sirupsen/logrus" + "io" "net" + "net/http" "os" "strings" "sync" @@ -46,6 +52,7 @@ import ( type traffic struct { controller + loginOpts edge.LoginOptions prefix string mode string cleanup bool @@ -60,7 +67,7 @@ type traffic struct { dialSPName string } -func NewVerifyTraffic() *cobra.Command { +func NewVerifyTraffic(out io.Writer, errOut io.Writer) *cobra.Command { t := &traffic{} cmd := &cobra.Command{ Use: "verify-traffic", @@ -97,9 +104,16 @@ func NewVerifyTraffic() *cobra.Command { t.clientIdName = t.prefix + ".client" t.bindSPName = t.prefix + ".bind" t.dialSPName = t.prefix + ".dial" - client, err := t.newMgmtClient() + client, err := mgmt.NewClient() if err != nil { - log.Fatal(err) + loginErr := t.loginOpts.Run() + if loginErr != nil { + log.Fatal(err) + } + client, err = mgmt.NewClient() + if err != nil { + log.Fatal(err) + } } t.client = client if t.cleanup { @@ -125,11 +139,12 @@ func NewVerifyTraffic() *cobra.Command { cmd.Flags().StringVarP(&t.prefix, "prefix", "x", "", "[optional] The prefix to apply to generated objects, necessary when not using the 'both' role.") cmd.Flags().StringVarP(&t.mode, "mode", "m", "", "[optional, default 'both'] The mode to perform: server, client, both.") cmd.Flags().BoolVar(&t.cleanup, "cleanup", false, "Whether to perform cleanup.") - cmd.Flags().BoolVar(&t.verbose, "verbose", false, "Show additional output.") cmd.Flags().BoolVar(&t.allowMultipleServers, "allow-multiple-servers", false, "Whether to allows the same server multiple times.") - cmd.Flags().StringVarP(&t.user, "username", "u", "", "username to use for authenticating to the Ziti Edge Controller ") - cmd.Flags().StringVarP(&t.pass, "password", "p", "", "password to use for authenticating to the Ziti Edge Controller, if -u is supplied and -p is not, a value will be prompted for") + edge.AddLoginFlags(cmd, &t.loginOpts) + t.loginOpts.Out = out + t.loginOpts.Err = errOut + cmd.Flags().StringVar(&t.host, "host", "", "the controller host") cmd.Flags().StringVar(&t.port, "port", "", "the controller port") @@ -315,7 +330,37 @@ func (t *traffic) newMgmtClient() (*rest_management_api_client.ZitiEdgeManagemen for _, ca := range caCerts { caPool.AddCert(ca) } - return rest_util.NewEdgeManagementClientWithUpdb(t.user, t.pass, ctrlAddress, caPool) + + cachedCreds, _, loadErr := util.LoadRestClientConfig() + if loadErr != nil { + log.Fatal(loadErr) + } + token := cachedCreds.EdgeIdentities[cachedCreds.Default].Token + tlsConfig := &tls.Config{ + RootCAs: caPool, + } + + transport := &http.Transport{ + TLSClientConfig: tlsConfig, + } + + // Assign the transport to the default HTTP client + http.DefaultClient = &http.Client{ + Transport: transport, + } + c, e := rest_util.NewEdgeManagementClientWithToken(http.DefaultClient, ctrlAddress, token) + if e != nil { + log.Fatal(e) + } + + p := &mgmtc.GetCurrentAPISessionParams{ + Context: context.Background(), + } + _, authErr := c.CurrentAPISession.GetCurrentAPISession(p, nil) + if authErr != nil { + log.Fatal("client not authenticated. login with 'ziti edge login' before executing") + } + return c, nil } func createIdentity(client *rest_management_api_client.ZitiEdgeManagement, name string, roleAttributes rest_model.Attributes) *identity.CreateIdentityCreated {