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 }