File: secrets.go

package info (click to toggle)
docker.io 26.1.5%2Bdfsg1-9
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 68,576 kB
  • sloc: sh: 5,748; makefile: 912; ansic: 664; asm: 228; python: 162
file content (131 lines) | stat: -rw-r--r-- 5,242 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package drivers

import (
	"fmt"

	"github.com/moby/swarmkit/v2/api"
	"github.com/moby/swarmkit/v2/api/naming"
	"github.com/moby/swarmkit/v2/node/plugin"
)

const (
	// SecretsProviderAPI is the endpoint for fetching secrets from plugins
	SecretsProviderAPI = "/SecretProvider.GetSecret"

	// SecretsProviderCapability is the secrets provider plugin capability identification
	SecretsProviderCapability = "secretprovider"
)

// SecretDriver provides secrets from different stores
type SecretDriver struct {
	plugin plugin.Plugin
}

// NewSecretDriver creates a new driver that provides third party secrets
func NewSecretDriver(plugin plugin.Plugin) *SecretDriver {
	return &SecretDriver{plugin: plugin}
}

// Get gets a secret from the secret provider. The function returns: the secret value;
// a bool indicating whether the value should be reused across different tasks (defaults to false);
// and an error if either the spec or task are nil, if calling the driver returns an error, or if
// the driver returns an error in the payload.
func (d *SecretDriver) Get(spec *api.SecretSpec, task *api.Task) ([]byte, bool, error) {
	if spec == nil {
		return nil, false, fmt.Errorf("secret spec is nil")
	}
	if task == nil {
		return nil, false, fmt.Errorf("task is nil")
	}

	var secretResp SecretsProviderResponse
	secretReq := &SecretsProviderRequest{
		SecretName:    spec.Annotations.Name,
		SecretLabels:  spec.Annotations.Labels,
		ServiceID:     task.ServiceID,
		ServiceName:   task.ServiceAnnotations.Name,
		ServiceLabels: task.ServiceAnnotations.Labels,
		TaskID:        task.ID,
		TaskName:      naming.Task(task),
		TaskImage:     task.Spec.GetContainer().Image,
		NodeID:        task.NodeID,
	}
	container := task.Spec.GetContainer()
	if container != nil {
		secretReq.ServiceHostname = container.Hostname
	}

	if task.Endpoint != nil && task.Endpoint.Spec != nil {
		secretReq.ServiceEndpointSpec = &EndpointSpec{
			Mode: int32(task.Endpoint.Spec.Mode),
		}
		for _, p := range task.Endpoint.Spec.Ports {
			if p == nil {
				continue
			}
			secretReq.ServiceEndpointSpec.Ports =
				append(secretReq.ServiceEndpointSpec.Ports,
					PortConfig{
						Name:          p.Name,
						Protocol:      int32(p.Protocol),
						PublishedPort: p.PublishedPort,
						TargetPort:    p.TargetPort,
						PublishMode:   int32(p.PublishMode),
					})
		}
	}

	err := d.plugin.Client().Call(SecretsProviderAPI, secretReq, &secretResp)
	if err != nil {
		return nil, false, err
	}
	if secretResp.Err != "" {
		return nil, secretResp.DoNotReuse, fmt.Errorf(secretResp.Err)
	}
	// Assign the secret value
	return secretResp.Value, secretResp.DoNotReuse, nil
}

// SecretsProviderRequest is the secrets provider request.
type SecretsProviderRequest struct {
	SecretName          string            `json:",omitempty"` // SecretName is the name of the secret to request from the plugin
	SecretLabels        map[string]string `json:",omitempty"` // SecretLabels capture environment names and other metadata pertaining to the secret
	ServiceHostname     string            `json:",omitempty"` // ServiceHostname is the hostname of the service, can be used for x509 certificate
	ServiceID           string            `json:",omitempty"` // ServiceID is the name of the service that requested the secret
	ServiceName         string            `json:",omitempty"` // ServiceName is the name of the service that requested the secret
	ServiceLabels       map[string]string `json:",omitempty"` // ServiceLabels capture environment names and other metadata pertaining to the service
	TaskID              string            `json:",omitempty"` // TaskID is the ID of the task that the secret will be assigned to
	TaskName            string            `json:",omitempty"` // TaskName is the name of the task that the secret will be assigned to
	TaskImage           string            `json:",omitempty"` // TaskName is the image of the task that the secret will be assigned to
	NodeID              string            `json:",omitempty"` // NodeID is the ID of the node that the task will be executed on
	ServiceEndpointSpec *EndpointSpec     `json:",omitempty"` // ServiceEndpointSpec holds the specification for endpoints
}

// SecretsProviderResponse is the secrets provider response.
type SecretsProviderResponse struct {
	Value []byte `json:",omitempty"` // Value is the value of the secret
	Err   string `json:",omitempty"` // Err is the error response of the plugin

	// DoNotReuse indicates that the secret returned from this request should
	// only be used for one task, and any further tasks should call the secret
	// driver again.
	DoNotReuse bool `json:",omitempty"`
}

// EndpointSpec represents the spec of an endpoint.
type EndpointSpec struct {
	Mode  int32        `json:",omitempty"`
	Ports []PortConfig `json:",omitempty"`
}

// PortConfig represents the config of a port.
type PortConfig struct {
	Name     string `json:",omitempty"`
	Protocol int32  `json:",omitempty"`
	// TargetPort is the port inside the container
	TargetPort uint32 `json:",omitempty"`
	// PublishedPort is the port on the swarm hosts
	PublishedPort uint32 `json:",omitempty"`
	// PublishMode is the mode in which port is published
	PublishMode int32 `json:",omitempty"`
}