Skip to content

Commit

Permalink
Plugable secret backend
Browse files Browse the repository at this point in the history
This commit extends SwarmKit secret management with pluggable secret
backends support.

Following previous commits:
1. moby/swarmkit@eebac27
2. moby/moby@08f7cf0

Added driver parameter to `docker secret` command.
Specifically:
1. `docker secret create [secret_name] --driver [driver_name]`
2.  Displaying the driver in
```
    $ docker secret ls
    $ docker secret inspect [secret_name]
    $ docker secret inspect [secret_name] -pretty
```
3. Add driver parameter to secrets in `docker-compose`.

There is a bug in serialization of the secret data. Handled in
moby/moby#34157.

Signed-off-by: Liron Levin <[email protected]>
  • Loading branch information
Liron Levin committed Jul 19, 2017
1 parent eedf0e3 commit b8f39b7
Show file tree
Hide file tree
Showing 24 changed files with 131 additions and 54 deletions.
26 changes: 21 additions & 5 deletions cli/command/formatter/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@ import (
)

const (
defaultSecretTableFormat = "table {{.ID}}\t{{.Name}}\t{{.CreatedAt}}\t{{.UpdatedAt}}"
defaultSecretTableFormat = "table {{.ID}}\t{{.Name}}\t{{.Driver}}\t{{.CreatedAt}}\t{{.UpdatedAt}}"
secretIDHeader = "ID"
secretCreatedHeader = "CREATED"
secretUpdatedHeader = "UPDATED"
secretInspectPrettyTemplate Format = `ID: {{.ID}}
Name: {{.Name}}
secretInspectPrettyTemplate Format = `ID: {{.ID}}
Name: {{.Name}}
{{- if .Labels }}
Labels:
{{- range $k, $v := .Labels }}
- {{ $k }}{{if $v }}={{ $v }}{{ end }}
{{- end }}{{ end }}
Created at: {{.CreatedAt}}
Updated at: {{.UpdatedAt}}`
Driver: {{.Driver}}
Created at: {{.CreatedAt}}
Updated at: {{.UpdatedAt}}`
)

// NewSecretFormat returns a Format for rendering using a secret Context
Expand Down Expand Up @@ -61,6 +62,7 @@ func newSecretContext() *secretContext {
sCtx.header = map[string]string{
"ID": secretIDHeader,
"Name": nameHeader,
"Driver": driverHeader,
"CreatedAt": secretCreatedHeader,
"UpdatedAt": secretUpdatedHeader,
"Labels": labelsHeader,
Expand Down Expand Up @@ -89,6 +91,13 @@ func (c *secretContext) CreatedAt() string {
return units.HumanDuration(time.Now().UTC().Sub(c.s.Meta.CreatedAt)) + " ago"
}

func (c *secretContext) Driver() string {
if c.s.Spec.Driver == nil {
return ""
}
return c.s.Spec.Driver.Name
}

func (c *secretContext) UpdatedAt() string {
return units.HumanDuration(time.Now().UTC().Sub(c.s.Meta.UpdatedAt)) + " ago"
}
Expand Down Expand Up @@ -153,6 +162,13 @@ func (ctx *secretInspectContext) Labels() map[string]string {
return ctx.Secret.Spec.Labels
}

func (ctx *secretInspectContext) Driver() string {
if ctx.Secret.Spec.Driver == nil {
return ""
}
return ctx.Secret.Spec.Driver.Name
}

func (ctx *secretInspectContext) CreatedAt() string {
return command.PrettyPrint(ctx.Secret.CreatedAt)
}
Expand Down
6 changes: 3 additions & 3 deletions cli/command/formatter/secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ func TestSecretContextFormatWrite(t *testing.T) {
},
// Table format
{Context{Format: NewSecretFormat("table", false)},
`ID NAME CREATED UPDATED
1 passwords Less than a second ago Less than a second ago
2 id_rsa Less than a second ago Less than a second ago
`ID NAME DRIVER CREATED UPDATED
1 passwords Less than a second ago Less than a second ago
2 id_rsa Less than a second ago Less than a second ago
`},
{Context{Format: NewSecretFormat("table {{.Name}}", true)},
`NAME
Expand Down
3 changes: 3 additions & 0 deletions cli/command/formatter/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,9 @@ func (c *serviceContext) Replicas() string {
}

func (c *serviceContext) Image() string {
if c.service.Spec.TaskTemplate.ContainerSpec == nil {
return ""
}
image := c.service.Spec.TaskTemplate.ContainerSpec.Image
if ref, err := reference.ParseNormalizedNamed(image); err == nil {
// update image string for display, (strips any digest)
Expand Down
48 changes: 35 additions & 13 deletions cli/command/secret/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

type createOptions struct {
name string
driver string
file string
labels opts.ListOpts
}
Expand All @@ -27,17 +28,20 @@ func newSecretCreateCommand(dockerCli command.Cli) *cobra.Command {
}

cmd := &cobra.Command{
Use: "create [OPTIONS] SECRET file|-",
Use: "create [OPTIONS] SECRET [file|-]",
Short: "Create a secret from a file or STDIN as content",
Args: cli.ExactArgs(2),
Args: cli.RequiresRangeArgs(1, 2),
RunE: func(cmd *cobra.Command, args []string) error {
options.name = args[0]
options.file = args[1]
if len(args) == 2 {
options.file = args[1]
}
return runSecretCreate(dockerCli, options)
},
}
flags := cmd.Flags()
flags.VarP(&options.labels, "label", "l", "Secret labels")
flags.StringVar(&options.driver, "driver", "", "Secret driver")

return cmd
}
Expand All @@ -46,28 +50,26 @@ func runSecretCreate(dockerCli command.Cli, options createOptions) error {
client := dockerCli.Client()
ctx := context.Background()

var in io.Reader = dockerCli.In()
if options.file != "-" {
file, err := system.OpenSequential(options.file)
if err != nil {
return err
}
in = file
defer file.Close()
if options.driver != "" && options.file != "" {
return errors.Errorf("When using secret driver secret data must be empty")
}

secretData, err := ioutil.ReadAll(in)
secretData, err := readSecretData(dockerCli.In(), options.file)
if err != nil {
return errors.Errorf("Error reading content from %q: %v", options.file, err)
}

spec := swarm.SecretSpec{
Annotations: swarm.Annotations{
Name: options.name,
Labels: opts.ConvertKVStringsToMap(options.labels.GetAll()),
},
Data: secretData,
}
if options.driver != "" {
spec.Driver = &swarm.Driver{
Name: options.driver,
}
}

r, err := client.SecretCreate(ctx, spec)
if err != nil {
Expand All @@ -77,3 +79,23 @@ func runSecretCreate(dockerCli command.Cli, options createOptions) error {
fmt.Fprintln(dockerCli.Out(), r.ID)
return nil
}

func readSecretData(in io.ReadCloser, file string) ([]byte, error) {
// Read secret value from external driver
if file == "" {
return nil, nil
}
if file != "-" {
var err error
in, err = system.OpenSequential(file)
if err != nil {
return nil, err
}
defer in.Close()
}
data, err := ioutil.ReadAll(in)
if err != nil {
return nil, err
}
return data, nil
}
6 changes: 1 addition & 5 deletions cli/command/secret/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,8 @@ func TestSecretCreateErrors(t *testing.T) {
secretCreateFunc func(swarm.SecretSpec) (types.SecretCreateResponse, error)
expectedError string
}{
{
args: []string{"too_few"},
expectedError: "requires exactly 2 argument(s)",
},
{args: []string{"too", "many", "arguments"},
expectedError: "requires exactly 2 argument(s)",
expectedError: "requires at least 1 and at most 2",
},
{
args: []string{"name", filepath.Join("testdata", secretDataFile)},
Expand Down
1 change: 1 addition & 0 deletions cli/command/secret/inspect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ func TestSecretInspectPretty(t *testing.T) {
}),
SecretID("secretID"),
SecretName("secretName"),
SecretDriver("driver"),
SecretCreatedAt(time.Time{}),
SecretUpdatedAt(time.Time{}),
), []byte{}, nil
Expand Down
1 change: 1 addition & 0 deletions cli/command/secret/ls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func TestSecretList(t *testing.T) {
SecretVersion(swarm.Version{Index: 11}),
SecretCreatedAt(time.Now().Add(-2*time.Hour)),
SecretUpdatedAt(time.Now().Add(-1*time.Hour)),
SecretDriver("driver"),
),
}, nil
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ ID: secretID
Name: secretName
Labels:
- lbl1=value1
Driver: driver
Created at: 0001-01-01 00:00:00+0000 utc
Updated at: 0001-01-01 00:00:00+0000 utc
6 changes: 3 additions & 3 deletions cli/command/secret/testdata/secret-list-with-filter.golden
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
ID NAME CREATED UPDATED
ID-foo foo 2 hours ago About an hour ago
ID-bar bar 2 hours ago About an hour ago
ID NAME DRIVER CREATED UPDATED
ID-foo foo 2 hours ago About an hour ago
ID-bar bar 2 hours ago About an hour ago
6 changes: 3 additions & 3 deletions cli/command/secret/testdata/secret-list.golden
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
ID NAME CREATED UPDATED
ID-foo foo 2 hours ago About an hour ago
ID-bar bar 2 hours ago About an hour ago
ID NAME DRIVER CREATED UPDATED
ID-foo foo 2 hours ago About an hour ago
ID-bar bar driver 2 hours ago About an hour ago
2 changes: 1 addition & 1 deletion cli/command/service/inspect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func formatServiceInspect(t *testing.T, format formatter.Format, now time.Time)
Labels: map[string]string{"com.label": "foo"},
},
TaskTemplate: swarm.TaskSpec{
ContainerSpec: swarm.ContainerSpec{
ContainerSpec: &swarm.ContainerSpec{
Image: "foo/bar@sha256:this_is_a_test",
},
Networks: []swarm.NetworkAttachmentConfig{
Expand Down
2 changes: 1 addition & 1 deletion cli/command/service/opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N
Labels: opts.ConvertKVStringsToMap(options.labels.GetAll()),
},
TaskTemplate: swarm.TaskSpec{
ContainerSpec: swarm.ContainerSpec{
ContainerSpec: &swarm.ContainerSpec{
Image: options.image,
Args: options.args,
Command: options.entrypoint.Value(),
Expand Down
2 changes: 1 addition & 1 deletion cli/command/service/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags
}
}

cspec := &spec.TaskTemplate.ContainerSpec
cspec := spec.TaskTemplate.ContainerSpec
task := &spec.TaskTemplate

taskResources := func() *swarm.ResourceRequirements {
Expand Down
12 changes: 6 additions & 6 deletions cli/command/service/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ func TestUpdateServiceArgs(t *testing.T) {
flags := newUpdateCommand(nil).Flags()
flags.Set("args", "the \"new args\"")

spec := &swarm.ServiceSpec{}
cspec := &spec.TaskTemplate.ContainerSpec
spec := &swarm.ServiceSpec{TaskTemplate: swarm.TaskSpec{ContainerSpec: &swarm.ContainerSpec{}}}
cspec := spec.TaskTemplate.ContainerSpec
cspec.Args = []string{"old", "args"}

updateService(nil, nil, flags, spec)
Expand Down Expand Up @@ -452,8 +452,8 @@ func TestUpdateSecretUpdateInPlace(t *testing.T) {
}

func TestUpdateReadOnly(t *testing.T) {
spec := &swarm.ServiceSpec{}
cspec := &spec.TaskTemplate.ContainerSpec
spec := &swarm.ServiceSpec{TaskTemplate: swarm.TaskSpec{ContainerSpec: &swarm.ContainerSpec{}}}
cspec := spec.TaskTemplate.ContainerSpec

// Update with --read-only=true, changed to true
flags := newUpdateCommand(nil).Flags()
Expand All @@ -474,8 +474,8 @@ func TestUpdateReadOnly(t *testing.T) {
}

func TestUpdateStopSignal(t *testing.T) {
spec := &swarm.ServiceSpec{}
cspec := &spec.TaskTemplate.ContainerSpec
spec := &swarm.ServiceSpec{TaskTemplate: swarm.TaskSpec{ContainerSpec: &swarm.ContainerSpec{}}}
cspec := spec.TaskTemplate.ContainerSpec

// Update with --stop-signal=SIGUSR1
flags := newUpdateCommand(nil).Flags()
Expand Down
2 changes: 1 addition & 1 deletion cli/command/stack/deploy_bundlefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func deployBundle(ctx context.Context, dockerCli command.Cli, opts deployOptions
Labels: convert.AddStackLabel(namespace, service.Labels),
},
TaskTemplate: swarm.TaskSpec{
ContainerSpec: swarm.ContainerSpec{
ContainerSpec: &swarm.ContainerSpec{
Image: service.Image,
Command: service.Command,
Args: service.Args,
Expand Down
18 changes: 14 additions & 4 deletions cli/compose/convert/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,27 @@ func Secrets(namespace Namespace, secrets map[string]composetypes.SecretConfig)
continue
}

data, err := ioutil.ReadFile(secret.File)
if err != nil {
return nil, err
var data []byte
var err error
var driver *swarm.Driver
if secret.Driver == "" {
data, err = ioutil.ReadFile(secret.File)
if err != nil {
return nil, err
}
} else {
driver = &swarm.Driver{
Name: secret.Driver,
}
}

result = append(result, swarm.SecretSpec{
Annotations: swarm.Annotations{
Name: namespace.Scope(name),
Labels: AddStackLabel(namespace, secret.Labels),
},
Data: data,
Data: data,
Driver: driver,
})
}
return result, nil
Expand Down
16 changes: 14 additions & 2 deletions cli/compose/convert/compose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
composetypes "github.com/docker/cli/cli/compose/types"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/pkg/testutil/tempfile"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -105,6 +106,7 @@ func TestNetworks(t *testing.T) {

func TestSecrets(t *testing.T) {
namespace := Namespace{name: "foo"}
const driver = "my-driver"

secretText := "this is the first secret"
secretFile := tempfile.NewTempFile(t, "convert-secrets", secretText)
Expand All @@ -120,12 +122,22 @@ func TestSecrets(t *testing.T) {
External: true,
},
},
"driver": {
Driver: driver,
},
}

specs, err := Secrets(namespace, source)
assert.NoError(t, err)
require.Len(t, specs, 1)
secret := specs[0]
require.Len(t, specs, 2)
secrets := make(map[string]swarm.SecretSpec)
for _, secret := range specs {
secrets[secret.Annotations.Name] = secret
}

assert.Equal(t, driver, secrets["foo_driver"].Driver.Name)

secret := secrets["foo_one"]
assert.Equal(t, "foo_one", secret.Name)
assert.Equal(t, map[string]string{
"monster": "mash",
Expand Down
2 changes: 1 addition & 1 deletion cli/compose/convert/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func Service(
Labels: AddStackLabel(namespace, service.Deploy.Labels),
},
TaskTemplate: swarm.TaskSpec{
ContainerSpec: swarm.ContainerSpec{
ContainerSpec: &swarm.ContainerSpec{
Image: service.Image,
Command: service.Entrypoint,
Args: service.Command,
Expand Down
Loading

0 comments on commit b8f39b7

Please sign in to comment.