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"`
}
|