github.com/argoproj/argo-cd/v3@v3.2.1/cmd/argocd/commands/gpg.go (about)

     1  package commands
     2  
     3  import (
     4  	stderrors "errors"
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  	"text/tabwriter"
     9  
    10  	"github.com/spf13/cobra"
    11  
    12  	"github.com/argoproj/argo-cd/v3/cmd/argocd/commands/headless"
    13  	"github.com/argoproj/argo-cd/v3/cmd/argocd/commands/utils"
    14  	argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient"
    15  	gpgkeypkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/gpgkey"
    16  	appsv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    17  	"github.com/argoproj/argo-cd/v3/util/errors"
    18  	utilio "github.com/argoproj/argo-cd/v3/util/io"
    19  	"github.com/argoproj/argo-cd/v3/util/templates"
    20  )
    21  
    22  // NewGPGCommand returns a new instance of an `argocd repo` command
    23  func NewGPGCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
    24  	command := &cobra.Command{
    25  		Use:   "gpg",
    26  		Short: "Manage GPG keys used for signature verification",
    27  		Run: func(c *cobra.Command, args []string) {
    28  			c.HelpFunc()(c, args)
    29  			os.Exit(1)
    30  		},
    31  		Example: ``,
    32  	}
    33  	command.AddCommand(NewGPGListCommand(clientOpts))
    34  	command.AddCommand(NewGPGGetCommand(clientOpts))
    35  	command.AddCommand(NewGPGAddCommand(clientOpts))
    36  	command.AddCommand(NewGPGDeleteCommand(clientOpts))
    37  	return command
    38  }
    39  
    40  // NewGPGListCommand lists all configured public keys from the server
    41  func NewGPGListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
    42  	var output string
    43  	command := &cobra.Command{
    44  		Use:   "list",
    45  		Short: "List configured GPG public keys",
    46  		Example: templates.Examples(`
    47    # List all configured GPG public keys in wide format (default).
    48    argocd gpg list
    49  		
    50    # List all configured GPG public keys in JSON format.
    51    argocd gpg list -o json
    52  		
    53    # List all configured GPG public keys in YAML format.
    54    argocd gpg list -o yaml
    55    		`),
    56  
    57  		Run: func(c *cobra.Command, _ []string) {
    58  			ctx := c.Context()
    59  
    60  			conn, gpgIf := headless.NewClientOrDie(clientOpts, c).NewGPGKeyClientOrDie()
    61  			defer utilio.Close(conn)
    62  			keys, err := gpgIf.List(ctx, &gpgkeypkg.GnuPGPublicKeyQuery{})
    63  			errors.CheckError(err)
    64  			switch output {
    65  			case "yaml", "json":
    66  				err := PrintResourceList(keys.Items, output, false)
    67  				errors.CheckError(err)
    68  			case "wide", "":
    69  				printKeyTable(keys.Items)
    70  			default:
    71  				errors.CheckError(fmt.Errorf("unknown output format: %s", output))
    72  			}
    73  		},
    74  	}
    75  	command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide")
    76  	return command
    77  }
    78  
    79  // NewGPGGetCommand retrieves a single public key from the server
    80  func NewGPGGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
    81  	var output string
    82  	command := &cobra.Command{
    83  		Use:   "get KEYID",
    84  		Short: "Get the GPG public key with ID <KEYID> from the server",
    85  		Example: templates.Examples(`  
    86    # Get a GPG public key with the specified KEYID in wide format (default).
    87    argocd gpg get KEYID
    88  		
    89    # Get a GPG public key with the specified KEYID in JSON format.
    90    argocd gpg get KEYID -o json
    91  		
    92    # Get a GPG public key with the specified KEYID in YAML format.
    93    argocd gpg get KEYID -o yaml
    94    		`),
    95  
    96  		Run: func(c *cobra.Command, args []string) {
    97  			ctx := c.Context()
    98  
    99  			if len(args) != 1 {
   100  				errors.Fatal(errors.ErrorGeneric, "Missing KEYID argument")
   101  			}
   102  			conn, gpgIf := headless.NewClientOrDie(clientOpts, c).NewGPGKeyClientOrDie()
   103  			defer utilio.Close(conn)
   104  			key, err := gpgIf.Get(ctx, &gpgkeypkg.GnuPGPublicKeyQuery{KeyID: args[0]})
   105  			errors.CheckError(err)
   106  			switch output {
   107  			case "yaml", "json":
   108  				err := PrintResourceList(key, output, false)
   109  				errors.CheckError(err)
   110  			case "wide", "":
   111  				fmt.Printf("Key ID:          %s\n", key.KeyID)
   112  				fmt.Printf("Key fingerprint: %s\n", key.Fingerprint)
   113  				fmt.Printf("Key subtype:     %s\n", strings.ToUpper(key.SubType))
   114  				fmt.Printf("Key owner:       %s\n", key.Owner)
   115  				fmt.Printf("Key data follows until EOF:\n%s\n", key.KeyData)
   116  			default:
   117  				errors.CheckError(fmt.Errorf("unknown output format: %s", output))
   118  			}
   119  		},
   120  	}
   121  	command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide")
   122  	return command
   123  }
   124  
   125  // NewGPGAddCommand adds a public key to the server's configuration
   126  func NewGPGAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
   127  	var fromFile string
   128  	command := &cobra.Command{
   129  		Use:   "add",
   130  		Short: "Adds a GPG public key to the server's keyring",
   131  		Example: templates.Examples(`
   132    # Add a GPG public key to the server's keyring from a file.
   133    argocd gpg add --from /path/to/keyfile
   134    		`),
   135  
   136  		Run: func(c *cobra.Command, _ []string) {
   137  			ctx := c.Context()
   138  
   139  			if fromFile == "" {
   140  				errors.CheckError(stderrors.New("--from is mandatory"))
   141  			}
   142  			keyData, err := os.ReadFile(fromFile)
   143  			if err != nil {
   144  				errors.CheckError(err)
   145  			}
   146  			conn, gpgIf := headless.NewClientOrDie(clientOpts, c).NewGPGKeyClientOrDie()
   147  			defer utilio.Close(conn)
   148  			resp, err := gpgIf.Create(ctx, &gpgkeypkg.GnuPGPublicKeyCreateRequest{Publickey: &appsv1.GnuPGPublicKey{KeyData: string(keyData)}})
   149  			errors.CheckError(err)
   150  			fmt.Printf("Created %d key(s) from input file", len(resp.Created.Items))
   151  			if len(resp.Skipped) > 0 {
   152  				fmt.Printf(", and %d key(s) were skipped because they exist already", len(resp.Skipped))
   153  			}
   154  			fmt.Printf(".\n")
   155  		},
   156  	}
   157  	command.Flags().StringVarP(&fromFile, "from", "f", "", "Path to the file that contains the GPG public key to import")
   158  	return command
   159  }
   160  
   161  // NewGPGDeleteCommand removes a key from the server's keyring
   162  func NewGPGDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
   163  	command := &cobra.Command{
   164  		Use:   "rm KEYID",
   165  		Short: "Removes a GPG public key from the server's keyring",
   166  		Run: func(c *cobra.Command, args []string) {
   167  			ctx := c.Context()
   168  
   169  			if len(args) != 1 {
   170  				errors.Fatal(errors.ErrorGeneric, "Missing KEYID argument")
   171  			}
   172  
   173  			keyId := args[0]
   174  
   175  			conn, gpgIf := headless.NewClientOrDie(clientOpts, c).NewGPGKeyClientOrDie()
   176  			defer utilio.Close(conn)
   177  
   178  			promptUtil := utils.NewPrompt(clientOpts.PromptsEnabled)
   179  			canDelete := promptUtil.Confirm(fmt.Sprintf("Are you sure you want to remove '%s'? [y/n] ", keyId))
   180  			if canDelete {
   181  				_, err := gpgIf.Delete(ctx, &gpgkeypkg.GnuPGPublicKeyQuery{KeyID: keyId})
   182  				errors.CheckError(err)
   183  				fmt.Printf("Deleted key with key ID %s\n", keyId)
   184  			} else {
   185  				fmt.Printf("The command to delete key with key ID '%s' was cancelled.\n", keyId)
   186  			}
   187  		},
   188  	}
   189  	return command
   190  }
   191  
   192  // Print table of certificate info
   193  func printKeyTable(keys []appsv1.GnuPGPublicKey) {
   194  	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
   195  	fmt.Fprintf(w, "KEYID\tTYPE\tIDENTITY\n")
   196  
   197  	for _, k := range keys {
   198  		fmt.Fprintf(w, "%s\t%s\t%s\n", k.KeyID, strings.ToUpper(k.SubType), k.Owner)
   199  	}
   200  	_ = w.Flush()
   201  }