secret.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. package controlapi
  2. import (
  3. "crypto/subtle"
  4. "strings"
  5. "github.com/docker/swarmkit/api"
  6. "github.com/docker/swarmkit/api/validation"
  7. "github.com/docker/swarmkit/identity"
  8. "github.com/docker/swarmkit/log"
  9. "github.com/docker/swarmkit/manager/state/store"
  10. "github.com/sirupsen/logrus"
  11. "golang.org/x/net/context"
  12. "google.golang.org/grpc/codes"
  13. "google.golang.org/grpc/status"
  14. )
  15. // assumes spec is not nil
  16. func secretFromSecretSpec(spec *api.SecretSpec) *api.Secret {
  17. return &api.Secret{
  18. ID: identity.NewID(),
  19. Spec: *spec,
  20. }
  21. }
  22. // GetSecret returns a `GetSecretResponse` with a `Secret` with the same
  23. // id as `GetSecretRequest.SecretID`
  24. // - Returns `NotFound` if the Secret with the given id is not found.
  25. // - Returns `InvalidArgument` if the `GetSecretRequest.SecretID` is empty.
  26. // - Returns an error if getting fails.
  27. func (s *Server) GetSecret(ctx context.Context, request *api.GetSecretRequest) (*api.GetSecretResponse, error) {
  28. if request.SecretID == "" {
  29. return nil, status.Errorf(codes.InvalidArgument, "secret ID must be provided")
  30. }
  31. var secret *api.Secret
  32. s.store.View(func(tx store.ReadTx) {
  33. secret = store.GetSecret(tx, request.SecretID)
  34. })
  35. if secret == nil {
  36. return nil, status.Errorf(codes.NotFound, "secret %s not found", request.SecretID)
  37. }
  38. secret.Spec.Data = nil // clean the actual secret data so it's never returned
  39. return &api.GetSecretResponse{Secret: secret}, nil
  40. }
  41. // UpdateSecret updates a Secret referenced by SecretID with the given SecretSpec.
  42. // - Returns `NotFound` if the Secret is not found.
  43. // - Returns `InvalidArgument` if the SecretSpec is malformed or anything other than Labels is changed
  44. // - Returns an error if the update fails.
  45. func (s *Server) UpdateSecret(ctx context.Context, request *api.UpdateSecretRequest) (*api.UpdateSecretResponse, error) {
  46. if request.SecretID == "" || request.SecretVersion == nil {
  47. return nil, status.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
  48. }
  49. var secret *api.Secret
  50. err := s.store.Update(func(tx store.Tx) error {
  51. secret = store.GetSecret(tx, request.SecretID)
  52. if secret == nil {
  53. return status.Errorf(codes.NotFound, "secret %s not found", request.SecretID)
  54. }
  55. // Check if the Name is different than the current name, or the secret is non-nil and different
  56. // than the current secret
  57. if secret.Spec.Annotations.Name != request.Spec.Annotations.Name ||
  58. (request.Spec.Data != nil && subtle.ConstantTimeCompare(request.Spec.Data, secret.Spec.Data) == 0) {
  59. return status.Errorf(codes.InvalidArgument, "only updates to Labels are allowed")
  60. }
  61. // We only allow updating Labels
  62. secret.Meta.Version = *request.SecretVersion
  63. secret.Spec.Annotations.Labels = request.Spec.Annotations.Labels
  64. return store.UpdateSecret(tx, secret)
  65. })
  66. if err != nil {
  67. return nil, err
  68. }
  69. log.G(ctx).WithFields(logrus.Fields{
  70. "secret.ID": request.SecretID,
  71. "secret.Name": request.Spec.Annotations.Name,
  72. "method": "UpdateSecret",
  73. }).Debugf("secret updated")
  74. // WARN: we should never return the actual secret data here. We need to redact the private fields first.
  75. secret.Spec.Data = nil
  76. return &api.UpdateSecretResponse{
  77. Secret: secret,
  78. }, nil
  79. }
  80. // ListSecrets returns a `ListSecretResponse` with a list all non-internal `Secret`s being
  81. // managed, or all secrets matching any name in `ListSecretsRequest.Names`, any
  82. // name prefix in `ListSecretsRequest.NamePrefixes`, any id in
  83. // `ListSecretsRequest.SecretIDs`, or any id prefix in `ListSecretsRequest.IDPrefixes`.
  84. // - Returns an error if listing fails.
  85. func (s *Server) ListSecrets(ctx context.Context, request *api.ListSecretsRequest) (*api.ListSecretsResponse, error) {
  86. var (
  87. secrets []*api.Secret
  88. respSecrets []*api.Secret
  89. err error
  90. byFilters []store.By
  91. by store.By
  92. labels map[string]string
  93. )
  94. // return all secrets that match either any of the names or any of the name prefixes (why would you give both?)
  95. if request.Filters != nil {
  96. for _, name := range request.Filters.Names {
  97. byFilters = append(byFilters, store.ByName(name))
  98. }
  99. for _, prefix := range request.Filters.NamePrefixes {
  100. byFilters = append(byFilters, store.ByNamePrefix(prefix))
  101. }
  102. for _, prefix := range request.Filters.IDPrefixes {
  103. byFilters = append(byFilters, store.ByIDPrefix(prefix))
  104. }
  105. labels = request.Filters.Labels
  106. }
  107. switch len(byFilters) {
  108. case 0:
  109. by = store.All
  110. case 1:
  111. by = byFilters[0]
  112. default:
  113. by = store.Or(byFilters...)
  114. }
  115. s.store.View(func(tx store.ReadTx) {
  116. secrets, err = store.FindSecrets(tx, by)
  117. })
  118. if err != nil {
  119. return nil, err
  120. }
  121. // strip secret data from the secret, filter by label, and filter out all internal secrets
  122. for _, secret := range secrets {
  123. if secret.Internal || !filterMatchLabels(secret.Spec.Annotations.Labels, labels) {
  124. continue
  125. }
  126. secret.Spec.Data = nil // clean the actual secret data so it's never returned
  127. respSecrets = append(respSecrets, secret)
  128. }
  129. return &api.ListSecretsResponse{Secrets: respSecrets}, nil
  130. }
  131. // CreateSecret creates and returns a `CreateSecretResponse` with a `Secret` based
  132. // on the provided `CreateSecretRequest.SecretSpec`.
  133. // - Returns `InvalidArgument` if the `CreateSecretRequest.SecretSpec` is malformed,
  134. // or if the secret data is too long or contains invalid characters.
  135. // - Returns an error if the creation fails.
  136. func (s *Server) CreateSecret(ctx context.Context, request *api.CreateSecretRequest) (*api.CreateSecretResponse, error) {
  137. if err := validateSecretSpec(request.Spec); err != nil {
  138. return nil, err
  139. }
  140. if request.Spec.Driver != nil { // Check that the requested driver is valid
  141. if _, err := s.dr.NewSecretDriver(request.Spec.Driver); err != nil {
  142. return nil, err
  143. }
  144. }
  145. secret := secretFromSecretSpec(request.Spec) // the store will handle name conflicts
  146. err := s.store.Update(func(tx store.Tx) error {
  147. return store.CreateSecret(tx, secret)
  148. })
  149. switch err {
  150. case store.ErrNameConflict:
  151. return nil, status.Errorf(codes.AlreadyExists, "secret %s already exists", request.Spec.Annotations.Name)
  152. case nil:
  153. secret.Spec.Data = nil // clean the actual secret data so it's never returned
  154. log.G(ctx).WithFields(logrus.Fields{
  155. "secret.Name": request.Spec.Annotations.Name,
  156. "method": "CreateSecret",
  157. }).Debugf("secret created")
  158. return &api.CreateSecretResponse{Secret: secret}, nil
  159. default:
  160. return nil, err
  161. }
  162. }
  163. // RemoveSecret removes the secret referenced by `RemoveSecretRequest.ID`.
  164. // - Returns `InvalidArgument` if `RemoveSecretRequest.ID` is empty.
  165. // - Returns `NotFound` if the a secret named `RemoveSecretRequest.ID` is not found.
  166. // - Returns `SecretInUse` if the secret is currently in use
  167. // - Returns an error if the deletion fails.
  168. func (s *Server) RemoveSecret(ctx context.Context, request *api.RemoveSecretRequest) (*api.RemoveSecretResponse, error) {
  169. if request.SecretID == "" {
  170. return nil, status.Errorf(codes.InvalidArgument, "secret ID must be provided")
  171. }
  172. err := s.store.Update(func(tx store.Tx) error {
  173. // Check if the secret exists
  174. secret := store.GetSecret(tx, request.SecretID)
  175. if secret == nil {
  176. return status.Errorf(codes.NotFound, "could not find secret %s", request.SecretID)
  177. }
  178. // Check if any services currently reference this secret, return error if so
  179. services, err := store.FindServices(tx, store.ByReferencedSecretID(request.SecretID))
  180. if err != nil {
  181. return status.Errorf(codes.Internal, "could not find services using secret %s: %v", request.SecretID, err)
  182. }
  183. if len(services) != 0 {
  184. serviceNames := make([]string, 0, len(services))
  185. for _, service := range services {
  186. serviceNames = append(serviceNames, service.Spec.Annotations.Name)
  187. }
  188. secretName := secret.Spec.Annotations.Name
  189. serviceNameStr := strings.Join(serviceNames, ", ")
  190. serviceStr := "services"
  191. if len(serviceNames) == 1 {
  192. serviceStr = "service"
  193. }
  194. return status.Errorf(codes.InvalidArgument, "secret '%s' is in use by the following %s: %v", secretName, serviceStr, serviceNameStr)
  195. }
  196. return store.DeleteSecret(tx, request.SecretID)
  197. })
  198. switch err {
  199. case store.ErrNotExist:
  200. return nil, status.Errorf(codes.NotFound, "secret %s not found", request.SecretID)
  201. case nil:
  202. log.G(ctx).WithFields(logrus.Fields{
  203. "secret.ID": request.SecretID,
  204. "method": "RemoveSecret",
  205. }).Debugf("secret removed")
  206. return &api.RemoveSecretResponse{}, nil
  207. default:
  208. return nil, err
  209. }
  210. }
  211. func validateSecretSpec(spec *api.SecretSpec) error {
  212. if spec == nil {
  213. return status.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
  214. }
  215. if err := validateConfigOrSecretAnnotations(spec.Annotations); err != nil {
  216. return err
  217. }
  218. // Check if secret driver is defined
  219. if spec.Driver != nil {
  220. // Ensure secret driver has a name
  221. if spec.Driver.Name == "" {
  222. return status.Errorf(codes.InvalidArgument, "secret driver must have a name")
  223. }
  224. return nil
  225. }
  226. if err := validation.ValidateSecretPayload(spec.Data); err != nil {
  227. return status.Errorf(codes.InvalidArgument, "%s", err.Error())
  228. }
  229. return nil
  230. }