From aeb96f27a235e2bb82953b0f1a051ea6f7124f28 Mon Sep 17 00:00:00 2001 From: Diogo Monica Date: Fri, 9 Oct 2015 21:36:37 -0700 Subject: [PATCH] Adding client-side root-ca server and config Signed-off-by: Diogo Monica --- cmd/notary/config.json | 7 +++++ cmd/notary/main.go | 66 +++++++++++++++++++++++++----------------- cmd/notary/tuf.go | 48 +++++++++++++++++++++++------- 3 files changed, 83 insertions(+), 38 deletions(-) create mode 100644 cmd/notary/config.json diff --git a/cmd/notary/config.json b/cmd/notary/config.json new file mode 100644 index 0000000000..bcc0f10cff --- /dev/null +++ b/cmd/notary/config.json @@ -0,0 +1,7 @@ +{ + "remote_server": { + "addr": "localhost:4443", + "root_ca": "./fixtures/root-ca.crt" + } +} + diff --git a/cmd/notary/main.go b/cmd/notary/main.go index 2f59fc3c36..a19440d7c4 100644 --- a/cmd/notary/main.go +++ b/cmd/notary/main.go @@ -7,24 +7,30 @@ import ( "strings" "github.com/Sirupsen/logrus" - "github.com/mitchellh/go-homedir" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/docker/notary/pkg/passphrase" "github.com/docker/notary/version" + homedir "github.com/mitchellh/go-homedir" + "github.com/spf13/cobra" + "github.com/spf13/viper" ) -const configFileName string = "config" -const defaultTrustDir string = ".notary/" -const defaultServerURL = "https://notary-server:4443" -const idSize = 64 +const ( + configDir = ".notary/" + defaultServerURL = "https://notary-server:4443" + idSize = 64 +) -var rawOutput bool -var trustDir string -var remoteTrustServer string -var verbose bool -var retriever passphrase.Retriever +var ( + rawOutput bool + verbose bool + trustDir string + configFile string + remoteTrustServer string + configPath string + configFileName = "config" + configFileExt = "json" + retriever passphrase.Retriever +) func init() { retriever = getPassphraseRetriever() @@ -45,17 +51,27 @@ func parseConfig() { if homeDir == "" { fatalf("cannot get current user home directory") } - trustDir = filepath.Join(homeDir, filepath.Dir(defaultTrustDir)) + trustDir = filepath.Join(homeDir, filepath.Dir(configDir)) logrus.Debugf("no trust directory provided, using default: %s", trustDir) } else { logrus.Debugf("trust directory provided: %s", trustDir) } - // Setup the configuration details + // If there was a commandline configFile set, we parse that. + // If there wasn't we attempt to find it on the default location ~/.notary/config + if configFile != "" { + configFileExt = strings.TrimPrefix(filepath.Ext(configFile), ".") + configFileName = strings.TrimSuffix(filepath.Base(configFile), filepath.Ext(configFile)) + configPath = filepath.Dir(configFile) + } else { + configPath = trustDir + } + + // Setup the configuration details into viper viper.SetConfigName(configFileName) - viper.AddConfigPath(trustDir) - viper.SetConfigType("json") + viper.SetConfigType(configFileExt) + viper.AddConfigPath(configPath) // Find and read the config file err := viper.ReadInConfig() @@ -69,11 +85,6 @@ func parseConfig() { } func main() { - serverURL := os.Getenv("NOTARY_SERVER_URL") - if serverURL == "" { - serverURL = defaultServerURL - } - var notaryCmd = &cobra.Command{ Use: "notary", Short: "notary allows the creation of trusted collections.", @@ -92,25 +103,26 @@ func main() { notaryCmd.AddCommand(versionCmd) notaryCmd.PersistentFlags().StringVarP(&trustDir, "trustdir", "d", "", "directory where the trust data is persisted to") + notaryCmd.PersistentFlags().StringVarP(&configFile, "configFile", "c", "", "path to the configuration file to use") notaryCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output") notaryCmd.AddCommand(cmdKey) notaryCmd.AddCommand(cmdCert) notaryCmd.AddCommand(cmdTufInit) - cmdTufInit.Flags().StringVarP(&remoteTrustServer, "server", "s", serverURL, "Remote trust server location") + cmdTufInit.Flags().StringVarP(&remoteTrustServer, "server", "s", "", "Remote trust server location") notaryCmd.AddCommand(cmdTufList) cmdTufList.Flags().BoolVarP(&rawOutput, "raw", "", false, "Instructs notary list to output a nonpretty printed version of the targets list. Useful if you need to parse the list.") - cmdTufList.Flags().StringVarP(&remoteTrustServer, "server", "s", serverURL, "Remote trust server location") + cmdTufList.Flags().StringVarP(&remoteTrustServer, "server", "s", "", "Remote trust server location") notaryCmd.AddCommand(cmdTufAdd) notaryCmd.AddCommand(cmdTufRemove) notaryCmd.AddCommand(cmdTufStatus) notaryCmd.AddCommand(cmdTufPublish) - cmdTufPublish.Flags().StringVarP(&remoteTrustServer, "server", "s", serverURL, "Remote trust server location") + cmdTufPublish.Flags().StringVarP(&remoteTrustServer, "server", "s", "", "Remote trust server location") notaryCmd.AddCommand(cmdTufLookup) cmdTufLookup.Flags().BoolVarP(&rawOutput, "raw", "", false, "Instructs notary lookup to output a nonpretty printed version of the targets list. Useful if you need to parse the list.") - cmdTufLookup.Flags().StringVarP(&remoteTrustServer, "server", "s", serverURL, "Remote trust server location") + cmdTufLookup.Flags().StringVarP(&remoteTrustServer, "server", "s", "", "Remote trust server location") notaryCmd.AddCommand(cmdVerify) - cmdVerify.Flags().StringVarP(&remoteTrustServer, "server", "s", serverURL, "Remote trust server location") + cmdVerify.Flags().StringVarP(&remoteTrustServer, "server", "s", "", "Remote trust server location") notaryCmd.Execute() } diff --git a/cmd/notary/tuf.go b/cmd/notary/tuf.go index 5273e614cd..0b36783155 100644 --- a/cmd/notary/tuf.go +++ b/cmd/notary/tuf.go @@ -4,6 +4,7 @@ import ( "bufio" "crypto/sha256" "crypto/tls" + "crypto/x509" "fmt" "io/ioutil" "net" @@ -20,6 +21,7 @@ import ( "github.com/docker/distribution/registry/client/transport" "github.com/docker/docker/pkg/term" notaryclient "github.com/docker/notary/client" + "github.com/docker/notary/trustmanager" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -93,7 +95,7 @@ func tufAdd(cmd *cobra.Command, args []string) { parseConfig() // no online operations are performed by add so the transport argument // should be nil - nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, nil, retriever) + nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), nil, retriever) if err != nil { fatalf(err.Error()) } @@ -118,7 +120,7 @@ func tufInit(cmd *cobra.Command, args []string) { gun := args[0] parseConfig() - nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, getTransport(gun, false), retriever) + nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), getTransport(gun, false), retriever) if err != nil { fatalf(err.Error()) } @@ -160,7 +162,7 @@ func tufList(cmd *cobra.Command, args []string) { gun := args[0] parseConfig() - nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, getTransport(gun, true), retriever) + nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), getTransport(gun, true), retriever) if err != nil { fatalf(err.Error()) } @@ -186,7 +188,7 @@ func tufLookup(cmd *cobra.Command, args []string) { targetName := args[1] parseConfig() - nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, getTransport(gun, true), retriever) + nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), getTransport(gun, true), retriever) if err != nil { fatalf(err.Error()) } @@ -208,7 +210,7 @@ func tufStatus(cmd *cobra.Command, args []string) { gun := args[0] parseConfig() - nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, nil, retriever) + nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), nil, retriever) if err != nil { fatalf(err.Error()) } @@ -242,7 +244,7 @@ func tufPublish(cmd *cobra.Command, args []string) { fmt.Println("Pushing changes to ", gun, ".") - nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, getTransport(gun, false), retriever) + nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), getTransport(gun, false), retriever) if err != nil { fatalf(err.Error()) } @@ -264,7 +266,7 @@ func tufRemove(cmd *cobra.Command, args []string) { // no online operation are performed by remove so the transport argument // should be nil. - repo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, nil, retriever) + repo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), nil, retriever) if err != nil { fatalf(err.Error()) } @@ -291,7 +293,7 @@ func verify(cmd *cobra.Command, args []string) { gun := args[0] targetName := args[1] - nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, getTransport(gun, true), retriever) + nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), getTransport(gun, true), retriever) if err != nil { fatalf(err.Error()) } @@ -357,11 +359,23 @@ func (ps passwordStore) Basic(u *url.URL) (string, string) { } func getTransport(gun string, readOnly bool) http.RoundTripper { + // Attempt to get a root CA from the config file. Nil is the host defaults. + rootPool := x509.NewCertPool() + rootCAFile := viper.GetString("remote_server.root_ca") + if rootCAFile != "" { + rootCert, err := trustmanager.LoadCertFromFile(viper.GetString("remote_server.root_ca")) + if err != nil { + rootPool = nil + } + rootPool.AddCert(rootCert) + } + // skipTLSVerify is false by default so verification will // be performed. tlsConfig := &tls.Config{ - InsecureSkipVerify: viper.GetBool("skipTLSVerify"), + InsecureSkipVerify: viper.GetBool("remote_server.skipTLSVerify"), MinVersion: tls.VersionTLS10, + RootCAs: rootPool, } base := &http.Transport{ @@ -386,9 +400,9 @@ func tokenAuth(baseTransport *http.Transport, gun string, readOnly bool) http.Ro Transport: authTransport, Timeout: 5 * time.Second, } - endpoint, err := url.Parse(remoteTrustServer) + endpoint, err := url.Parse(getRemoteTrustServer()) if err != nil { - fatalf("could not parse remote trust server url (%s): %s", remoteTrustServer, err.Error()) + fatalf("could not parse remote trust server url (%s): %s", getRemoteTrustServer(), err.Error()) } subPath, err := url.Parse("v2/") if err != nil { @@ -416,3 +430,15 @@ func tokenAuth(baseTransport *http.Transport, gun string, readOnly bool) http.Ro modifier := transport.RequestModifier(auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler)) return transport.NewTransport(baseTransport, modifier) } + +func getRemoteTrustServer() string { + if remoteTrustServer == "" { + configRemote := viper.GetString("remote_server.addr") + if configRemote != "" { + remoteTrustServer = configRemote + } else { + remoteTrustServer = defaultServerURL + } + } + return remoteTrustServer +}