docs: add docs for new trust subcommands

Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
Kyle Spiers 2017-09-26 11:46:38 -07:00 committed by Riyaz Faizullabhoy
parent 604bc3f22d
commit 4e797eaa04
6 changed files with 520 additions and 69 deletions

View File

@ -23,9 +23,9 @@ func newKeyGenerateCommand(dockerCli command.Streams) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "key-generate NAME [NAME...]", Use: "key-generate NAME [NAME...]",
Short: "Generate and load a signing key-pair", Short: "Generate and load a signing key-pair",
Args: cli.RequiresMinArgs(1), Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return setupPassphraseAndGenerateKeys(dockerCli, args) return setupPassphraseAndGenerateKeys(dockerCli, args[0])
}, },
} }
return cmd return cmd
@ -36,56 +36,41 @@ var validKeyName = regexp.MustCompile(`^[a-zA-Z0-9\_]+[a-zA-Z0-9\_\-]*$`).MatchS
// validate that all of the key names are unique and are alphanumeric + _ + - // validate that all of the key names are unique and are alphanumeric + _ + -
// and that we do not already have public key files in the current dir on disk // and that we do not already have public key files in the current dir on disk
func validateKeyArgs(keyNames []string, cwdPath string) error { func validateKeyArgs(keyName string, cwdPath string) error {
uniqueKeyNames := map[string]struct{}{}
for _, keyName := range keyNames {
if !validKeyName(keyName) { if !validKeyName(keyName) {
return fmt.Errorf("key name \"%s\" must not contain special characters", keyName) return fmt.Errorf("key name \"%s\" must not contain special characters", keyName)
} }
if _, ok := uniqueKeyNames[keyName]; ok {
return fmt.Errorf("key names must be unique, found duplicate key name: \"%s\"", keyName)
}
uniqueKeyNames[keyName] = struct{}{}
pubKeyFileName := keyName + ".pub" pubKeyFileName := keyName + ".pub"
if _, err := os.Stat(filepath.Join(cwdPath, pubKeyFileName)); err == nil { if _, err := os.Stat(filepath.Join(cwdPath, pubKeyFileName)); err == nil {
return fmt.Errorf("public key file already exists: \"%s\"", pubKeyFileName) return fmt.Errorf("public key file already exists: \"%s\"", pubKeyFileName)
} }
}
return nil return nil
} }
func setupPassphraseAndGenerateKeys(streams command.Streams, keyNames []string) error { func setupPassphraseAndGenerateKeys(streams command.Streams, keyName string) error {
// always use a fresh passphrase for each key generation // always use a fresh passphrase for each key generation
freshPassRetGetter := func() notary.PassRetriever { return trust.GetPassphraseRetriever(streams.In(), streams.Out()) } freshPassRetGetter := func() notary.PassRetriever { return trust.GetPassphraseRetriever(streams.In(), streams.Out()) }
cwd, err := os.Getwd() cwd, err := os.Getwd()
if err != nil { if err != nil {
return err return err
} }
return generateKeys(streams, keyNames, cwd, freshPassRetGetter) return validateAndGenerateKey(streams, keyName, cwd, freshPassRetGetter)
} }
func generateKeys(streams command.Streams, keyNames []string, workingDir string, passphraseGetter func() notary.PassRetriever) error { func validateAndGenerateKey(streams command.Streams, keyName string, workingDir string, passphraseGetter func() notary.PassRetriever) error {
var genKeyErrs []string if err := validateKeyArgs(keyName, workingDir); err != nil {
if err := validateKeyArgs(keyNames, workingDir); err != nil {
return err return err
} }
for _, keyName := range keyNames {
fmt.Fprintf(streams.Out(), "\nGenerating key for %s...\n", keyName) fmt.Fprintf(streams.Out(), "\nGenerating key for %s...\n", keyName)
freshPassRet := passphraseGetter() freshPassRet := passphraseGetter()
if err := generateKey(keyName, workingDir, trust.GetTrustDirectory(), freshPassRet); err != nil { if err := generateKey(keyName, workingDir, trust.GetTrustDirectory(), freshPassRet); err != nil {
fmt.Fprintf(streams.Out(), err.Error()) fmt.Fprintf(streams.Out(), err.Error())
genKeyErrs = append(genKeyErrs, keyName) return fmt.Errorf("Error generating key for: %s", keyName)
} else { }
pubFileName := strings.Join([]string{keyName, "pub"}, ".") pubFileName := strings.Join([]string{keyName, "pub"}, ".")
fmt.Fprintf(streams.Out(), "Successfully generated and loaded private key. Corresponding public key available: %s\n", pubFileName) fmt.Fprintf(streams.Out(), "Successfully generated and loaded private key. Corresponding public key available: %s\n", pubFileName)
}
}
if len(genKeyErrs) > 0 {
return fmt.Errorf("Error generating keys for: %s", strings.Join(genKeyErrs, ", "))
}
return nil return nil
} }

View File

@ -24,9 +24,15 @@ func TestTrustKeyGenerateErrors(t *testing.T) {
}{ }{
{ {
name: "not-enough-args", name: "not-enough-args",
expectedError: "requires at least 1 argument", expectedError: "requires exactly 1 argument",
},
{
name: "too-many-args",
args: []string{"key-1", "key-2"},
expectedError: "requires exactly 1 argument",
}, },
} }
tmpDir, err := ioutil.TempDir("", "docker-key-generate-test-") tmpDir, err := ioutil.TempDir("", "docker-key-generate-test-")
assert.NoError(t, err) assert.NoError(t, err)
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
@ -106,48 +112,19 @@ func TestValidateKeyArgs(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
defer os.RemoveAll(pubKeyCWD) defer os.RemoveAll(pubKeyCWD)
err = validateKeyArgs([]string{"a", "b", "C_123", "key-name"}, pubKeyCWD) err = validateKeyArgs("a", pubKeyCWD)
assert.NoError(t, err) assert.NoError(t, err)
err = validateKeyArgs([]string{"a", "a"}, pubKeyCWD) err = validateKeyArgs("a/b", pubKeyCWD)
assert.Error(t, err)
assert.Equal(t, err.Error(), "key names must be unique, found duplicate key name: \"a\"")
err = validateKeyArgs([]string{"a/b"}, pubKeyCWD)
assert.Error(t, err) assert.Error(t, err)
assert.Equal(t, err.Error(), "key name \"a/b\" must not contain special characters") assert.Equal(t, err.Error(), "key name \"a/b\" must not contain special characters")
err = validateKeyArgs([]string{"-"}, pubKeyCWD) err = validateKeyArgs("-", pubKeyCWD)
assert.Error(t, err) assert.Error(t, err)
assert.Equal(t, err.Error(), "key name \"-\" must not contain special characters") assert.Equal(t, err.Error(), "key name \"-\" must not contain special characters")
assert.NoError(t, ioutil.WriteFile(filepath.Join(pubKeyCWD, "a.pub"), []byte("abc"), notary.PrivExecPerms)) assert.NoError(t, ioutil.WriteFile(filepath.Join(pubKeyCWD, "a.pub"), []byte("abc"), notary.PrivExecPerms))
err = validateKeyArgs([]string{"a"}, pubKeyCWD) err = validateKeyArgs("a", pubKeyCWD)
assert.Error(t, err) assert.Error(t, err)
assert.Equal(t, err.Error(), "public key file already exists: \"a.pub\"") assert.Equal(t, err.Error(), "public key file already exists: \"a.pub\"")
} }
func TestGenerateMultipleKeysOutput(t *testing.T) {
pubKeyCWD, err := ioutil.TempDir("", "pub-keys-")
assert.NoError(t, err)
defer os.RemoveAll(pubKeyCWD)
passwd := "password"
cannedPasswordRetriever := func() notary.PassRetriever { return passphrase.ConstantRetriever(passwd) }
cli := test.NewFakeCli(&fakeClient{})
assert.NoError(t, generateKeys(cli, []string{"alice", "bob", "charlie"}, pubKeyCWD, cannedPasswordRetriever))
// Check the stdout prints:
assert.Contains(t, cli.OutBuffer().String(), "\nGenerating key for alice...\n")
assert.Contains(t, cli.OutBuffer().String(), "Successfully generated and loaded private key. Corresponding public key available: alice.pub\n")
assert.Contains(t, cli.OutBuffer().String(), "\nGenerating key for bob...\n")
assert.Contains(t, cli.OutBuffer().String(), "Successfully generated and loaded private key. Corresponding public key available: bob.pub\n")
assert.Contains(t, cli.OutBuffer().String(), "\nGenerating key for charlie...\n")
assert.Contains(t, cli.OutBuffer().String(), "Successfully generated and loaded private key. Corresponding public key available: charlie.pub\n")
// Check that we have three key files:
cwdKeyFiles, err := ioutil.ReadDir(pubKeyCWD)
assert.NoError(t, err)
assert.Len(t, cwdKeyFiles, 3)
}

View File

@ -0,0 +1,52 @@
---
title: "key-generate"
description: "The key-generate command description and usage"
keywords: "Key, notary, trust"
---
<!-- This file is maintained within the docker/cli Github
repository at https://github.com/docker/cli/. Make all
pull requests against that repo. If you see this file in
another repository, consider it read-only there, as it will
periodically be overwritten by the definitive file. Pull
requests which include edits to this file in other repositories
will be rejected.
-->
# trust key-generate
```markdown
Usage: docker trust key-generate NAME
Generate and load a signing key-pair
```
## Description
`docker trust key-generate` generates a key-pair to be used with signing,
and loads the private key into the local docker trust keystore.
`docker trust key-generate` is currently experimental.
## Examples
### Generate a key-pair
```bash
$ docker trust key-generate alice
Generating key for alice...
Enter passphrase for new alice key with ID 17acf3c:
Repeat passphrase for new alice key with ID 17acf3c:
Successfully generated and loaded private key. Corresponding public key available: alice.pub
$ ls
alice.pub
```
The private signing key is encrypted by the passphrase and loaded into the docker trust keystore.
All passphrase requests to sign with the key will be referred to by the provided `NAME`.
The public key component `alice.pub` will be available in the current working directory, and can
be used directly by `docker trust signer-add`.

View File

@ -0,0 +1,56 @@
---
title: "key-load"
description: "The key-load command description and usage"
keywords: "Key, notary, trust"
---
<!-- This file is maintained within the docker/cli Github
repository at https://github.com/docker/cli/. Make all
pull requests against that repo. If you see this file in
another repository, consider it read-only there, as it will
periodically be overwritten by the definitive file. Pull
requests which include edits to this file in other repositories
will be rejected.
-->
# trust key-load
```markdown
Usage: docker trust key-load [OPTIONS] KEY
Load a signing key
```
## Description
`docker trust key-load` adds private keys to the local docker trust keystore. To add a signer to a repository use `docker trust signer-add`.
`docker trust key-load` is currently experimental.
## Examples
### Load a single private key
For a private key `alice.pem` with permissions `-rw-------`
```bash
$ docker trust key-load alice.pem
Loading key from "alice.pem"...
Enter passphrase for new signer key with ID f8097df:
Repeat passphrase for new signer key with ID f8097df:
Successfully imported key from alice.pem
```
to specify a name use the `--name` flag
```bash
$ docker trust key-load --name alice-key alice.pem
Loading key from "alice.pem"...
Enter passphrase for new alice-key key with ID f8097df:
Repeat passphrase for new alice-key key with ID f8097df:
Successfully imported key from alice.pem
```

View File

@ -0,0 +1,213 @@
---
title: "signer-add"
description: "The signer-add command description and usage"
keywords: "signer, notary, trust"
---
<!-- This file is maintained within the docker/cli Github
repository at https://github.com/docker/cli/. Make all
pull requests against that repo. If you see this file in
another repository, consider it read-only there, as it will
periodically be overwritten by the definitive file. Pull
requests which include edits to this file in other repositories
will be rejected.
-->
# trust signer-add
```markdown
Usage: docker trust signer-add [OPTIONS] NAME IMAGE [IMAGE...]
Add a signer to one or more repositories
```
## Description
`docker trust signer-add` adds signers to signed repositories.
`docker trust signer-add` is currently experimental.
## Examples
### Add a signer to a repo
To add a new signer, `alice`, to this repository:
```bash
$ docker trust inspect example/trust-demo
No signatures for example/trust-demo
List of signers and their keys:
SIGNER KEYS
bob 5600f5ab76a2
Administrative keys for example/trust-demo:
Repository Key: 642692c14c9fc399da523a5f4e24fe306a0a6ee1cc79a10e4555b3c6ab02f71e
Root Key: 3cb2228f6561e58f46dbc4cda4fcaff9d5ef22e865a94636f82450d1d2234949
```
Add `alice` with `docker trust signer-add`:
```bash
$ docker trust signer-add alice example/trust-demo --key alice.crt
Adding signer "alice" to example/trust-demo...
Enter passphrase for repository key with ID 642692c:
Successfully added signer: alice to example/trust-demo
```
`docker trust inspect` now lists `alice` as a valid signer:
```bash
$ docker trust inspect example/trust-demo
No signatures for example/trust-demo
List of signers and their keys:
SIGNER KEYS
alice 05e87edcaecb
bob 5600f5ab76a2
Administrative keys for example/trust-demo:
Repository Key: 642692c14c9fc399da523a5f4e24fe306a0a6ee1cc79a10e4555b3c6ab02f71e
Root Key: 3cb2228f6561e58f46dbc4cda4fcaff9d5ef22e865a94636f82450d1d2234949
```
## Initialize a new repo and add a signer
When adding a signer on a repo for the first time, `docker trust signer-add` sets up a new repo if it doesn't exist.
```bash
$ docker trust inspect example/trust-demo
No signatures or cannot access example/trust-demo
```
```bash
$ docker trust signer-add alice example/trust-demo --key alice.crt
Initializing signed repository for example/trust-demo...
Enter passphrase for root key with ID 748121c:
Enter passphrase for new repository key with ID 95b9e55:
Repeat passphrase for new repository key with ID 95b9e55:
Successfully initialized "example/trust-demo"
Adding signer "alice" to example/trust-demo...
Successfully added signer: alice to example/trust-demo
```
```bash
$ docker trust inspect example/trust-demo
No signatures for example/trust-demo
SIGNED TAG DIGEST SIGNERS
List of signers and their keys:
SIGNER KEYS
alice 6d52b29d940f
Administrative keys for example/trust-demo:
Repository Key: 95b9e5565eac3ef5ec01406801bdfb70feb40c17808d2222427c18046eb63beb
Root Key: 748121c14bd1461f6c58cb3ef39087c8fdc7633bb11a98af844fd9a04e208103
```
## Add a signer to multiple repos
To add a signer, `alice`, to multiple repositories:
```bash
$ docker trust inspect example/trust-demo
SIGNED TAG DIGEST SIGNERS
v1 74d4bfa917d55d53c7df3d2ab20a8d926874d61c3da5ef6de15dd2654fc467c4 bob
List of signers and their keys:
SIGNER KEYS
bob 5600f5ab76a2
Administrative keys for example/trust-demo:
Repository Key: ecc457614c9fc399da523a5f4e24fe306a0a6ee1cc79a10e4555b3c6ab02f71e
Root Key: 3cb2228f6561e58f46dbc4cda4fcaff9d5ef22e865a94636f82450d1d2234949
```
```bash
$ docker trust inspect example/trust-demo2
SIGNED TAG DIGEST SIGNERS
v1 74d4bfa917d55d53c7df3d2ab20a8d926874d61c3da5ef6de15dd2654fc467c4 bob
List of signers and their keys:
SIGNER KEYS
bob 5600f5ab76a2
Administrative keys for example/trust-demo2:
Repository Key: ece554f14c9fc399da523a5f4e24fe306a0a6ee1cc79a10e4553d2ab20a8d9268
Root Key: 3cb2228f6561e58f46dbc4cda4fcaff9d5ef22e865a94636f82450d1d2234949
```
Add `alice` to both repositories with a single `docker trust signer-add` command:
```bash
$ docker trust signer-add alice example/trust-demo example/trust-demo2 -k alice.crt
Adding signer "alice" to example/trust-demo...
Enter passphrase for repository key with ID 95b9e55:
Successfully added signer: alice to example/trust-demo
Adding signer "alice" to example/trust-demo2...
Enter passphrase for repository key with ID ece554f:
Successfully added signer: alice to example/trust-demo2
```
`docker trust inspect` now lists `alice` as a valid signer of both `example/trust-demo` and `example/trust-demo2`:
```bash
$ docker trust inspect example/trust-demo
SIGNED TAG DIGEST SIGNERS
v1 74d4bfa917d55d53c7df3d2ab20a8d926874d61c3da5ef6de15dd2654fc467c4 bob
List of signers and their keys:
SIGNER KEYS
alice 05e87edcaecb
bob 5600f5ab76a2
Administrative keys for example/trust-demo:
Repository Key: 95b9e5514c9fc399da523a5f4e24fe306a0a6ee1cc79a10e4555b3c6ab02f71e
Root Key: 3cb2228f6561e58f46dbc4cda4fcaff9d5ef22e865a94636f82450d1d2234949
```
```bash
$ docker trust inspect example/trust-demo2
SIGNED TAG DIGEST SIGNERS
v1 74d4bfa917d55d53c7df3d2ab20a8d926874d61c3da5ef6de15dd2654fc467c4 bob
List of signers and their keys:
SIGNER KEYS
alice 05e87edcaecb
bob 5600f5ab76a2
Administrative keys for example/trust-demo2:
Repository Key: ece554f14c9fc399da523a5f4e24fe306a0a6ee1cc79a10e4553d2ab20a8d9268
Root Key: 3cb2228f6561e58f46dbc4cda4fcaff9d5ef22e865a94636f82450d1d2234949
```
`docker trust signer-add` adds signers to repositories on a best effort basis, so it will continue to add the signer to subsequent repositories if one attempt fails:
```bash
$ docker trust signer-add alice example/unauthorized example/authorized -k alice.crt
Adding signer "alice" to example/unauthorized...
you are not authorized to perform this operation: server returned 401.
Adding signer "alice" to example/authorized...
Enter passphrase for repository key with ID c6772a0:
Successfully added signer: alice to example/authorized
Failed to add signer to: example/unauthorized
```

View File

@ -0,0 +1,168 @@
---
title: "signer-remove"
description: "The signer-remove command description and usage"
keywords: "signer, notary, trust"
---
<!-- This file is maintained within the docker/cli Github
repository at https://github.com/docker/cli/. Make all
pull requests against that repo. If you see this file in
another repository, consider it read-only there, as it will
periodically be overwritten by the definitive file. Pull
requests which include edits to this file in other repositories
will be rejected.
-->
# trust signer-remove
```markdown
Usage: docker trust signer-remove [OPTIONS] NAME IMAGE [IMAGE...]
Remove a signer from one or more repositories
```
## Description
`docker trust signer-remove` removes signers from signed repositories.
`docker trust signer-remove` is currently experimental.
## Examples
### Remove a signer from a repo
To remove an existing signer, `alice`, from this repository:
```bash
$ docker trust inspect example/trust-demo
No signatures for example/trust-demo
List of signers and their keys:
SIGNER KEYS
alice 05e87edcaecb
bob 5600f5ab76a2
Administrative keys for example/trust-demo:
Repository Key: ecc457614c9fc399da523a5f4e24fe306a0a6ee1cc79a10e4555b3c6ab02f71e
Root Key: 3cb2228f6561e58f46dbc4cda4fcaff9d5ef22e865a94636f82450d1d2234949
```
Remove `alice` with `docker trust signer-remove`:
```bash
$ docker trust signer-remove alice example/trust-demo
Enter passphrase for repository key with ID 642692c:
Successfully removed alice from example/trust-demo
```
`docker trust inspect` now does not list `alice` as a valid signer:
```bash
$ docker trust inspect example/trust-demo
No signatures for example/trust-demo
List of signers and their keys:
SIGNER KEYS
bob 5600f5ab76a2
Administrative keys for example/trust-demo:
Repository Key: ecc457614c9fc399da523a5f4e24fe306a0a6ee1cc79a10e4555b3c6ab02f71e
Root Key: 3cb2228f6561e58f46dbc4cda4fcaff9d5ef22e865a94636f82450d1d2234949
```
### Remove a signer from multiple repos
To remove an existing signer, `alice`, from multiple repositories:
```bash
$ docker trust inspect example/trust-demo
SIGNED TAG DIGEST SIGNERS
v1 74d4bfa917d55d53c7df3d2ab20a8d926874d61c3da5ef6de15dd2654fc467c4 alice, bob
List of signers and their keys:
SIGNER KEYS
alice 05e87edcaecb
bob 5600f5ab76a2
Administrative keys for example/trust-demo:
Repository Key: 95b9e5514c9fc399da523a5f4e24fe306a0a6ee1cc79a10e4555b3c6ab02f71e
Root Key: 3cb2228f6561e58f46dbc4cda4fcaff9d5ef22e865a94636f82450d1d2234949
```
```bash
$ docker trust inspect example/trust-demo2
SIGNED TAG DIGEST SIGNERS
v1 74d4bfa917d55d53c7df3d2ab20a8d926874d61c3da5ef6de15dd2654fc467c4 alice, bob
List of signers and their keys:
SIGNER KEYS
alice 05e87edcaecb
bob 5600f5ab76a2
Administrative keys for example/trust-demo2:
Repository Key: ece554f14c9fc399da523a5f4e24fe306a0a6ee1cc79a10e4553d2ab20a8d9268
Root Key: 3cb2228f6561e58f46dbc4cda4fcaff9d5ef22e865a94636f82450d1d2234949
```
Remove `alice` from both images with a single `docker trust signer-remove` command:
```bash
$ docker trust signer-remove alice example/trust-demo example/trust-demo2
Enter passphrase for repository key with ID 95b9e55:
Successfully removed alice from example/trust-demo
Enter passphrase for repository key with ID ece554f:
Successfully removed alice from example/trust-demo2
```
`docker trust inspect` no longer lists `alice` as a valid signer of either `example/trust-demo` or `example/trust-demo2`:
```bash
$ docker trust inspect example/trust-demo
SIGNED TAG DIGEST SIGNERS
v1 74d4bfa917d55d53c7df3d2ab20a8d926874d61c3da5ef6de15dd2654fc467c4 bob
List of signers and their keys:
SIGNER KEYS
bob 5600f5ab76a2
Administrative keys for example/trust-demo:
Repository Key: ecc457614c9fc399da523a5f4e24fe306a0a6ee1cc79a10e4555b3c6ab02f71e
Root Key: 3cb2228f6561e58f46dbc4cda4fcaff9d5ef22e865a94636f82450d1d2234949
```
```bash
$ docker trust inspect example/trust-demo2
SIGNED TAG DIGEST SIGNERS
v1 74d4bfa917d55d53c7df3d2ab20a8d926874d61c3da5ef6de15dd2654fc467c4 bob
List of signers and their keys:
SIGNER KEYS
bob 5600f5ab76a2
Administrative keys for example/trust-demo2:
Repository Key: ece554f14c9fc399da523a5f4e24fe306a0a6ee1cc79a10e4553d2ab20a8d9268
Root Key: 3cb2228f6561e58f46dbc4cda4fcaff9d5ef22e865a94636f82450d1d2234949
```
`docker trust signer-remove` removes signers to repositories on a best effort basis, so it will continue to remove the signer from subsequent repositories if one attempt fails:
```bash
$ docker trust signer-remove alice example/unauthorized example/authorized
Removing signer "alice" from image example/unauthorized...
No signer alice for image example/unauthorized
Removing signer "alice" from image example/authorized...
Enter passphrase for repository key with ID c6772a0:
Successfully removed alice from example/authorized
Error removing signer from: example/unauthorized
```