mirror of https://github.com/docker/docs.git
190 lines
5.9 KiB
Go
190 lines
5.9 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/x509"
|
|
"fmt"
|
|
"path/filepath"
|
|
|
|
"github.com/docker/notary"
|
|
notaryclient "github.com/docker/notary/client"
|
|
"github.com/docker/notary/passphrase"
|
|
"github.com/docker/notary/trustmanager"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
var cmdCertTemplate = usageTemplate{
|
|
Use: "cert",
|
|
Short: "Operates on certificates.",
|
|
Long: `Operations on certificates.`,
|
|
}
|
|
|
|
var cmdCertListTemplate = usageTemplate{
|
|
Use: "list",
|
|
Short: "Lists certificates.",
|
|
Long: "Lists root certificates known to notary.",
|
|
}
|
|
|
|
var cmdCertRemoveTemplate = usageTemplate{
|
|
Use: "remove [ certID ]",
|
|
Short: "Removes the certificate with the given cert ID.",
|
|
Long: "Remove the certificate with the given cert ID from the local host.",
|
|
}
|
|
|
|
type certCommander struct {
|
|
// these need to be set
|
|
configGetter func() (*viper.Viper, error)
|
|
retriever passphrase.Retriever
|
|
|
|
// these are for command line parsing - no need to set
|
|
certRemoveGUN string
|
|
certRemoveYes bool
|
|
}
|
|
|
|
func (c *certCommander) GetCommand() *cobra.Command {
|
|
cmd := cmdCertTemplate.ToCommand(nil)
|
|
cmd.AddCommand(cmdCertListTemplate.ToCommand(c.certList))
|
|
|
|
cmdCertRemove := cmdCertRemoveTemplate.ToCommand(c.certRemove)
|
|
cmdCertRemove.Flags().StringVarP(
|
|
&c.certRemoveGUN, "gun", "g", "", "Globally unique name to delete certificates for")
|
|
cmdCertRemove.Flags().BoolVarP(
|
|
&c.certRemoveYes, "yes", "y", false, "Answer yes to the removal question (no confirmation)")
|
|
|
|
cmd.AddCommand(cmdCertRemove)
|
|
|
|
return cmd
|
|
}
|
|
|
|
// certRemove deletes a certificate given a cert ID or a gun
|
|
// If given a gun, certRemove will also remove local TUF data
|
|
func (c *certCommander) certRemove(cmd *cobra.Command, args []string) error {
|
|
// If the user hasn't provided -g with a gun, or a cert ID, show usage
|
|
// If the user provided -g and a cert ID, also show usage
|
|
if (len(args) < 1 && c.certRemoveGUN == "") || (len(args) > 0 && c.certRemoveGUN != "") {
|
|
cmd.Usage()
|
|
return fmt.Errorf("Must specify the cert ID or the GUN of the certificates to remove")
|
|
}
|
|
config, err := c.configGetter()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
trustDir := config.GetString("trust_dir")
|
|
certPath := filepath.Join(trustDir, notary.TrustedCertsDir)
|
|
certStore, err := trustmanager.NewX509FilteredFileStore(
|
|
certPath,
|
|
trustmanager.FilterCertsExpiredSha1,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to create a new truststore with directory: %s", trustDir)
|
|
}
|
|
|
|
var certsToRemove []*x509.Certificate
|
|
var certFoundByID *x509.Certificate
|
|
var removeTrustData bool
|
|
|
|
// If there is no GUN, we expect a cert ID
|
|
if c.certRemoveGUN == "" {
|
|
certID := args[0]
|
|
// Attempt to find this certificate
|
|
certFoundByID, err = certStore.GetCertificateByCertID(certID)
|
|
if err != nil {
|
|
// This is an invalid ID, the user might have forgotten a character
|
|
if len(certID) != notary.Sha256HexSize {
|
|
return fmt.Errorf("Unable to retrieve certificate with invalid certificate ID provided: %s", certID)
|
|
}
|
|
return fmt.Errorf("Unable to retrieve certificate with cert ID: %s", certID)
|
|
}
|
|
// the GUN is the CN from the certificate
|
|
c.certRemoveGUN = certFoundByID.Subject.CommonName
|
|
certsToRemove = []*x509.Certificate{certFoundByID}
|
|
}
|
|
|
|
toRemove, err := certStore.GetCertificatesByCN(c.certRemoveGUN)
|
|
// We could not find any certificates matching the user's query, so propagate the error
|
|
if err != nil {
|
|
return fmt.Errorf("%v", err)
|
|
}
|
|
|
|
// If we specified a GUN or if the ID we specified is the only certificate with its CN, remove all GUN certs and trust data too
|
|
if certFoundByID == nil || len(toRemove) == 1 {
|
|
removeTrustData = true
|
|
certsToRemove = toRemove
|
|
}
|
|
|
|
// List all the certificates about to be removed
|
|
cmd.Printf("The following certificates will be removed:\n\n")
|
|
for _, cert := range certsToRemove {
|
|
// This error can't occur because we're getting certs off of an
|
|
// x509 store that indexes by ID.
|
|
certID, _ := trustmanager.FingerprintCert(cert)
|
|
cmd.Printf("%s - %s\n", cert.Subject.CommonName, certID)
|
|
}
|
|
// If we were given a GUN or the last ID for a GUN, inform the user that we'll also delete all TUF data
|
|
if removeTrustData {
|
|
cmd.Printf("\nAll local trust data will be removed for %s\n", c.certRemoveGUN)
|
|
}
|
|
cmd.Println("\nAre you sure you want to remove these certificates? (yes/no)")
|
|
|
|
// Ask for confirmation before removing certificates, unless -y is provided
|
|
if !c.certRemoveYes {
|
|
confirmed := askConfirm()
|
|
if !confirmed {
|
|
return fmt.Errorf("Aborting action.")
|
|
}
|
|
}
|
|
|
|
if removeTrustData {
|
|
// Remove all TUF data, so call RemoveTrustData on a NotaryRepository with the GUN
|
|
// no online operations are performed so the transport argument is nil
|
|
nRepo, err := notaryclient.NewNotaryRepository(
|
|
trustDir, c.certRemoveGUN, getRemoteTrustServer(config), nil, c.retriever)
|
|
if err != nil {
|
|
return fmt.Errorf("Could not establish trust data for GUN %s", c.certRemoveGUN)
|
|
}
|
|
// DeleteTrustData will pick up all of the same certificates by GUN (CN) and remove them
|
|
err = nRepo.DeleteTrustData()
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to delete trust data for %s", c.certRemoveGUN)
|
|
}
|
|
} else {
|
|
for _, cert := range certsToRemove {
|
|
err = certStore.RemoveCert(cert)
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to remove cert %s", cert)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *certCommander) certList(cmd *cobra.Command, args []string) error {
|
|
if len(args) > 0 {
|
|
cmd.Usage()
|
|
return fmt.Errorf("")
|
|
}
|
|
config, err := c.configGetter()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
trustDir := config.GetString("trust_dir")
|
|
certPath := filepath.Join(trustDir, notary.TrustedCertsDir)
|
|
// Load all individual (non-CA) certificates that aren't expired and don't use SHA1
|
|
certStore, err := trustmanager.NewX509FilteredFileStore(
|
|
certPath,
|
|
trustmanager.FilterCertsExpiredSha1,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to create a new truststore with directory: %s", trustDir)
|
|
}
|
|
|
|
trustedCerts := certStore.GetCertificates()
|
|
|
|
cmd.Println("")
|
|
prettyPrintCerts(trustedCerts, cmd.Out())
|
|
cmd.Println("")
|
|
return nil
|
|
}
|