mirror of https://github.com/docker/docs.git
				
				
				
			
		
			
				
	
	
		
			359 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			359 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Go
		
	
	
	
| package main
 | |
| 
 | |
| import (
 | |
| 	"archive/zip"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"sort"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/docker/notary"
 | |
| 	notaryclient "github.com/docker/notary/client"
 | |
| 	"github.com/docker/notary/cryptoservice"
 | |
| 	"github.com/docker/notary/passphrase"
 | |
| 	"github.com/docker/notary/signer/api"
 | |
| 	"github.com/docker/notary/trustmanager"
 | |
| 
 | |
| 	"github.com/docker/notary/tuf/data"
 | |
| 	"github.com/docker/notary/tuf/signed"
 | |
| 	"github.com/spf13/cobra"
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	cmdKey.AddCommand(cmdKeyList)
 | |
| 	cmdKey.AddCommand(cmdKeyGenerateRootKey)
 | |
| 
 | |
| 	cmdKeyExport.Flags().StringVarP(&keysExportGUN, "gun", "g", "", "Globally unique name to export keys for")
 | |
| 	cmdKey.AddCommand(cmdKeyExport)
 | |
| 	cmdKey.AddCommand(cmdKeyExportRoot)
 | |
| 	cmdKeyExportRoot.Flags().BoolVarP(&keysExportRootChangePassphrase, "change-passphrase", "p", false, "set a new passphrase for the key being exported")
 | |
| 	cmdKey.AddCommand(cmdKeyImport)
 | |
| 	cmdKey.AddCommand(cmdKeyImportRoot)
 | |
| 	cmdKey.AddCommand(cmdRotateKey)
 | |
| }
 | |
| 
 | |
| var cmdKey = &cobra.Command{
 | |
| 	Use:   "key",
 | |
| 	Short: "Operates on keys.",
 | |
| 	Long:  `operations on private keys.`,
 | |
| }
 | |
| 
 | |
| var cmdKeyList = &cobra.Command{
 | |
| 	Use:   "list",
 | |
| 	Short: "Lists keys.",
 | |
| 	Long:  "lists keys known to notary.",
 | |
| 	Run:   keysList,
 | |
| }
 | |
| 
 | |
| var cmdRotateKey = &cobra.Command{
 | |
| 	Use:   "rotate [ GUN ]",
 | |
| 	Short: "Rotate all keys for role.",
 | |
| 	Long:  "Removes all old keys for the given role and generates 1 new key.",
 | |
| 	Run:   keysRotate,
 | |
| }
 | |
| 
 | |
| var cmdKeyGenerateRootKey = &cobra.Command{
 | |
| 	Use:   "generate [ algorithm ]",
 | |
| 	Short: "Generates a new root key with a given algorithm.",
 | |
| 	Long:  "generates a new root key with a given algorithm.",
 | |
| 	Run:   keysGenerateRootKey,
 | |
| }
 | |
| 
 | |
| var keysExportGUN string
 | |
| 
 | |
| var cmdKeyExport = &cobra.Command{
 | |
| 	Use:   "export [ filename ]",
 | |
| 	Short: "Exports keys to a ZIP file.",
 | |
| 	Long:  "exports a collection of keys. The keys are reencrypted with a new passphrase. The output is a ZIP file.",
 | |
| 	Run:   keysExport,
 | |
| }
 | |
| 
 | |
| var keysExportRootChangePassphrase bool
 | |
| 
 | |
| var cmdKeyExportRoot = &cobra.Command{
 | |
| 	Use:   "export-root [ keyID ] [ filename ]",
 | |
| 	Short: "Exports given root key to a file.",
 | |
| 	Long:  "exports a root key, without reencrypting. The output is a PEM file.",
 | |
| 	Run:   keysExportRoot,
 | |
| }
 | |
| 
 | |
| var cmdKeyImport = &cobra.Command{
 | |
| 	Use:   "import [ filename ]",
 | |
| 	Short: "Imports keys from a ZIP file.",
 | |
| 	Long:  "imports one or more keys from a ZIP file.",
 | |
| 	Run:   keysImport,
 | |
| }
 | |
| 
 | |
| var cmdKeyImportRoot = &cobra.Command{
 | |
| 	Use:   "import-root [ filename ]",
 | |
| 	Short: "Imports root key.",
 | |
| 	Long:  "imports a root key from a PEM file.",
 | |
| 	Run:   keysImportRoot,
 | |
| }
 | |
| 
 | |
| func keysList(cmd *cobra.Command, args []string) {
 | |
| 	if len(args) > 0 {
 | |
| 		cmd.Usage()
 | |
| 		os.Exit(1)
 | |
| 	}
 | |
| 
 | |
| 	parseConfig()
 | |
| 
 | |
| 	keysPath := filepath.Join(trustDir, notary.PrivDir)
 | |
| 	fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, retriever)
 | |
| 	if err != nil {
 | |
| 		fatalf("failed to create private key store in directory: %s", keysPath)
 | |
| 	}
 | |
| 	yubiStore, _ := api.NewYubiKeyStore(fileKeyStore, retriever)
 | |
| 	var cs signed.CryptoService
 | |
| 	if yubiStore == nil {
 | |
| 		cs = cryptoservice.NewCryptoService("", fileKeyStore)
 | |
| 	} else {
 | |
| 		cs = cryptoservice.NewCryptoService("", yubiStore, fileKeyStore)
 | |
| 	}
 | |
| 
 | |
| 	// Get a map of all the keys/roles
 | |
| 	keysMap := cs.ListAllKeys()
 | |
| 
 | |
| 	fmt.Println("")
 | |
| 	fmt.Println("# Root keys: ")
 | |
| 	for k, v := range keysMap {
 | |
| 		if v == "root" {
 | |
| 			fmt.Println(k)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	fmt.Println("")
 | |
| 	fmt.Println("# Signing keys: ")
 | |
| 
 | |
| 	// Get a list of all the keys
 | |
| 	var sortedKeys []string
 | |
| 	for k := range keysMap {
 | |
| 		sortedKeys = append(sortedKeys, k)
 | |
| 	}
 | |
| 	// Sort the list of all the keys
 | |
| 	sort.Strings(sortedKeys)
 | |
| 
 | |
| 	// Print a sorted list of the key/role
 | |
| 	for _, k := range sortedKeys {
 | |
| 		if keysMap[k] != "root" {
 | |
| 			printKey(k, keysMap[k])
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func keysGenerateRootKey(cmd *cobra.Command, args []string) {
 | |
| 	if len(args) < 1 {
 | |
| 		cmd.Usage()
 | |
| 		fatalf("must specify an Algorithm (RSA, ECDSA)")
 | |
| 	}
 | |
| 
 | |
| 	algorithm := args[0]
 | |
| 	allowedCiphers := map[string]bool{
 | |
| 		"rsa":   true,
 | |
| 		"ecdsa": true,
 | |
| 	}
 | |
| 
 | |
| 	if !allowedCiphers[strings.ToLower(algorithm)] {
 | |
| 		fatalf("algorithm not allowed, possible values are: RSA, ECDSA")
 | |
| 	}
 | |
| 
 | |
| 	parseConfig()
 | |
| 
 | |
| 	keysPath := filepath.Join(trustDir, notary.PrivDir)
 | |
| 	fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, retriever)
 | |
| 	if err != nil {
 | |
| 		fatalf("failed to create private key store in directory: %s", keysPath)
 | |
| 	}
 | |
| 	yubiStore, err := api.NewYubiKeyStore(fileKeyStore, retriever)
 | |
| 	var cs signed.CryptoService
 | |
| 	if err != nil {
 | |
| 		cmd.Printf("No Yubikey detected, importing to local filesystem.")
 | |
| 		cs = cryptoservice.NewCryptoService("", fileKeyStore)
 | |
| 	} else {
 | |
| 		cs = cryptoservice.NewCryptoService("", yubiStore, fileKeyStore)
 | |
| 	}
 | |
| 
 | |
| 	pubKey, err := cs.Create(data.CanonicalRootRole, algorithm)
 | |
| 	if err != nil {
 | |
| 		fatalf("failed to create a new root key: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	fmt.Printf("Generated new %s root key with keyID: %s\n", algorithm, pubKey.ID())
 | |
| }
 | |
| 
 | |
| // keysExport exports a collection of keys to a ZIP file
 | |
| func keysExport(cmd *cobra.Command, args []string) {
 | |
| 	if len(args) < 1 {
 | |
| 		cmd.Usage()
 | |
| 		fatalf("must specify output filename for export")
 | |
| 	}
 | |
| 
 | |
| 	exportFilename := args[0]
 | |
| 
 | |
| 	parseConfig()
 | |
| 
 | |
| 	keysPath := filepath.Join(trustDir, notary.PrivDir)
 | |
| 	fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, retriever)
 | |
| 	if err != nil {
 | |
| 		fatalf("failed to create private key store in directory: %s", keysPath)
 | |
| 	}
 | |
| 	cs := cryptoservice.NewCryptoService("", fileKeyStore)
 | |
| 
 | |
| 	exportFile, err := os.Create(exportFilename)
 | |
| 	if err != nil {
 | |
| 		fatalf("error creating output file: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Must use a different passphrase retriever to avoid caching the
 | |
| 	// unlocking passphrase and reusing that.
 | |
| 	exportRetriever := passphrase.PromptRetriever()
 | |
| 	if keysExportGUN != "" {
 | |
| 		err = cs.ExportKeysByGUN(exportFile, keysExportGUN, exportRetriever)
 | |
| 	} else {
 | |
| 		err = cs.ExportAllKeys(exportFile, exportRetriever)
 | |
| 	}
 | |
| 
 | |
| 	exportFile.Close()
 | |
| 
 | |
| 	if err != nil {
 | |
| 		os.Remove(exportFilename)
 | |
| 		fatalf("error exporting keys: %v", err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // keysExportRoot exports a root key by ID to a PEM file
 | |
| func keysExportRoot(cmd *cobra.Command, args []string) {
 | |
| 	if len(args) < 2 {
 | |
| 		cmd.Usage()
 | |
| 		fatalf("must specify key ID and output filename for export")
 | |
| 	}
 | |
| 
 | |
| 	keyID := args[0]
 | |
| 	exportFilename := args[1]
 | |
| 
 | |
| 	if len(keyID) != idSize {
 | |
| 		fatalf("please specify a valid root key ID")
 | |
| 	}
 | |
| 
 | |
| 	parseConfig()
 | |
| 
 | |
| 	keysPath := filepath.Join(trustDir, notary.PrivDir)
 | |
| 	fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, retriever)
 | |
| 	if err != nil {
 | |
| 		fatalf("failed to create private key store in directory: %s", keysPath)
 | |
| 	}
 | |
| 	cs := cryptoservice.NewCryptoService("", fileKeyStore)
 | |
| 
 | |
| 	exportFile, err := os.Create(exportFilename)
 | |
| 	if err != nil {
 | |
| 		fatalf("error creating output file: %v", err)
 | |
| 	}
 | |
| 	if keysExportRootChangePassphrase {
 | |
| 		// Must use a different passphrase retriever to avoid caching the
 | |
| 		// unlocking passphrase and reusing that.
 | |
| 		exportRetriever := passphrase.PromptRetriever()
 | |
| 		err = cs.ExportRootKeyReencrypt(exportFile, keyID, exportRetriever)
 | |
| 	} else {
 | |
| 		err = cs.ExportRootKey(exportFile, keyID)
 | |
| 	}
 | |
| 	exportFile.Close()
 | |
| 	if err != nil {
 | |
| 		os.Remove(exportFilename)
 | |
| 		fatalf("error exporting root key: %v", err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // keysImport imports keys from a ZIP file
 | |
| func keysImport(cmd *cobra.Command, args []string) {
 | |
| 	if len(args) < 1 {
 | |
| 		cmd.Usage()
 | |
| 		fatalf("must specify input filename for import")
 | |
| 	}
 | |
| 
 | |
| 	importFilename := args[0]
 | |
| 
 | |
| 	parseConfig()
 | |
| 
 | |
| 	keysPath := filepath.Join(trustDir, notary.PrivDir)
 | |
| 	fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, retriever)
 | |
| 	if err != nil {
 | |
| 		fatalf("failed to create private key store in directory: %s", keysPath)
 | |
| 	}
 | |
| 	cs := cryptoservice.NewCryptoService("", fileKeyStore)
 | |
| 
 | |
| 	zipReader, err := zip.OpenReader(importFilename)
 | |
| 	if err != nil {
 | |
| 		fatalf("opening file for import: %v", err)
 | |
| 	}
 | |
| 	defer zipReader.Close()
 | |
| 
 | |
| 	err = cs.ImportKeysZip(zipReader.Reader)
 | |
| 
 | |
| 	if err != nil {
 | |
| 		fatalf("error importing keys: %v", err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // keysImportRoot imports a root key from a PEM file
 | |
| func keysImportRoot(cmd *cobra.Command, args []string) {
 | |
| 	if len(args) != 1 {
 | |
| 		cmd.Usage()
 | |
| 		fatalf("must specify input filename for import")
 | |
| 	}
 | |
| 
 | |
| 	importFilename := args[0]
 | |
| 
 | |
| 	parseConfig()
 | |
| 
 | |
| 	keysPath := filepath.Join(trustDir, notary.PrivDir)
 | |
| 	fileKeyStore, err := trustmanager.NewKeyFileStore(keysPath, retriever)
 | |
| 	if err != nil {
 | |
| 		fatalf("failed to create private key store in directory: %s", keysPath)
 | |
| 	}
 | |
| 	yubiStore, err := api.NewYubiKeyStore(fileKeyStore, retriever)
 | |
| 	var cs signed.CryptoService
 | |
| 	if err != nil {
 | |
| 		cmd.Printf("No Yubikey detected, importing to local filesystem.")
 | |
| 		cs = cryptoservice.NewCryptoService("", fileKeyStore)
 | |
| 	} else {
 | |
| 		cs = cryptoservice.NewCryptoService("", yubiStore, fileKeyStore)
 | |
| 	}
 | |
| 
 | |
| 	importFile, err := os.Open(importFilename)
 | |
| 	if err != nil {
 | |
| 		fatalf("opening file for import: %v", err)
 | |
| 	}
 | |
| 	defer importFile.Close()
 | |
| 
 | |
| 	err = cs.ImportRootKey(importFile)
 | |
| 
 | |
| 	if err != nil {
 | |
| 		fatalf("error importing root key: %v", err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func printKey(keyPath, alias string) {
 | |
| 	keyID := filepath.Base(keyPath)
 | |
| 	gun := filepath.Dir(keyPath)
 | |
| 	fmt.Printf("%s - %s - %s\n", gun, alias, keyID)
 | |
| }
 | |
| 
 | |
| func keysRotate(cmd *cobra.Command, args []string) {
 | |
| 	if len(args) < 1 {
 | |
| 		cmd.Usage()
 | |
| 		fatalf("must specify a GUN and target")
 | |
| 	}
 | |
| 	parseConfig()
 | |
| 
 | |
| 	gun := args[0]
 | |
| 	nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, nil, retriever)
 | |
| 	if err != nil {
 | |
| 		fatalf(err.Error())
 | |
| 	}
 | |
| 	if err := nRepo.RotateKeys(); err != nil {
 | |
| 		fatalf(err.Error())
 | |
| 	}
 | |
| }
 |