trust_server.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "net"
  6. "net/http"
  7. "os"
  8. "os/exec"
  9. "path/filepath"
  10. "strings"
  11. "time"
  12. "github.com/docker/docker/cliconfig"
  13. "github.com/docker/docker/pkg/tlsconfig"
  14. "github.com/docker/notary/client"
  15. "github.com/docker/notary/passphrase"
  16. "github.com/docker/notary/tuf/data"
  17. "github.com/go-check/check"
  18. )
  19. var notaryBinary = "notary-server"
  20. var notaryClientBinary = "notary"
  21. type testNotary struct {
  22. cmd *exec.Cmd
  23. dir string
  24. }
  25. const notaryHost = "localhost:4443"
  26. const notaryURL = "https://" + notaryHost
  27. func newTestNotary(c *check.C) (*testNotary, error) {
  28. // generate server config
  29. template := `{
  30. "server": {
  31. "http_addr": "%s",
  32. "tls_key_file": "%s",
  33. "tls_cert_file": "%s"
  34. },
  35. "trust_service": {
  36. "type": "local",
  37. "hostname": "",
  38. "port": "",
  39. "key_algorithm": "ed25519"
  40. },
  41. "logging": {
  42. "level": "debug"
  43. },
  44. "storage": {
  45. "backend": "memory"
  46. }
  47. }`
  48. tmp, err := ioutil.TempDir("", "notary-test-")
  49. if err != nil {
  50. return nil, err
  51. }
  52. confPath := filepath.Join(tmp, "config.json")
  53. config, err := os.Create(confPath)
  54. defer config.Close()
  55. if err != nil {
  56. return nil, err
  57. }
  58. workingDir, err := os.Getwd()
  59. if err != nil {
  60. return nil, err
  61. }
  62. if _, err := fmt.Fprintf(config, template, notaryHost, filepath.Join(workingDir, "fixtures/notary/localhost.key"), filepath.Join(workingDir, "fixtures/notary/localhost.cert")); err != nil {
  63. os.RemoveAll(tmp)
  64. return nil, err
  65. }
  66. // generate client config
  67. clientConfPath := filepath.Join(tmp, "client-config.json")
  68. clientConfig, err := os.Create(clientConfPath)
  69. defer clientConfig.Close()
  70. if err != nil {
  71. return nil, err
  72. }
  73. template = `{
  74. "trust_dir" : "%s",
  75. "remote_server": {
  76. "url": "%s",
  77. "skipTLSVerify": true
  78. }
  79. }`
  80. if _, err = fmt.Fprintf(clientConfig, template, filepath.Join(cliconfig.ConfigDir(), "trust"), notaryURL); err != nil {
  81. os.RemoveAll(tmp)
  82. return nil, err
  83. }
  84. // run notary-server
  85. cmd := exec.Command(notaryBinary, "-config", confPath)
  86. if err := cmd.Start(); err != nil {
  87. os.RemoveAll(tmp)
  88. if os.IsNotExist(err) {
  89. c.Skip(err.Error())
  90. }
  91. return nil, err
  92. }
  93. testNotary := &testNotary{
  94. cmd: cmd,
  95. dir: tmp,
  96. }
  97. // Wait for notary to be ready to serve requests.
  98. for i := 1; i <= 20; i++ {
  99. if err = testNotary.Ping(); err == nil {
  100. break
  101. }
  102. time.Sleep(10 * time.Millisecond * time.Duration(i*i))
  103. }
  104. if err != nil {
  105. c.Fatalf("Timeout waiting for test notary to become available: %s", err)
  106. }
  107. return testNotary, nil
  108. }
  109. func (t *testNotary) Ping() error {
  110. tlsConfig := tlsconfig.ClientDefault
  111. tlsConfig.InsecureSkipVerify = true
  112. client := http.Client{
  113. Transport: &http.Transport{
  114. Proxy: http.ProxyFromEnvironment,
  115. Dial: (&net.Dialer{
  116. Timeout: 30 * time.Second,
  117. KeepAlive: 30 * time.Second,
  118. }).Dial,
  119. TLSHandshakeTimeout: 10 * time.Second,
  120. TLSClientConfig: &tlsConfig,
  121. },
  122. }
  123. resp, err := client.Get(fmt.Sprintf("%s/v2/", notaryURL))
  124. if err != nil {
  125. return err
  126. }
  127. if resp.StatusCode != 200 {
  128. return fmt.Errorf("notary ping replied with an unexpected status code %d", resp.StatusCode)
  129. }
  130. return nil
  131. }
  132. func (t *testNotary) Close() {
  133. t.cmd.Process.Kill()
  134. os.RemoveAll(t.dir)
  135. }
  136. func (s *DockerTrustSuite) trustedCmd(cmd *exec.Cmd) {
  137. pwd := "12345678"
  138. trustCmdEnv(cmd, notaryURL, pwd, pwd)
  139. }
  140. func (s *DockerTrustSuite) trustedCmdWithServer(cmd *exec.Cmd, server string) {
  141. pwd := "12345678"
  142. trustCmdEnv(cmd, server, pwd, pwd)
  143. }
  144. func (s *DockerTrustSuite) trustedCmdWithPassphrases(cmd *exec.Cmd, rootPwd, repositoryPwd string) {
  145. trustCmdEnv(cmd, notaryURL, rootPwd, repositoryPwd)
  146. }
  147. func (s *DockerTrustSuite) trustedCmdWithDeprecatedEnvPassphrases(cmd *exec.Cmd, offlinePwd, taggingPwd string) {
  148. trustCmdDeprecatedEnv(cmd, notaryURL, offlinePwd, taggingPwd)
  149. }
  150. func trustCmdEnv(cmd *exec.Cmd, server, rootPwd, repositoryPwd string) {
  151. env := []string{
  152. "DOCKER_CONTENT_TRUST=1",
  153. fmt.Sprintf("DOCKER_CONTENT_TRUST_SERVER=%s", server),
  154. fmt.Sprintf("DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE=%s", rootPwd),
  155. fmt.Sprintf("DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE=%s", repositoryPwd),
  156. }
  157. cmd.Env = append(os.Environ(), env...)
  158. }
  159. // Helper method to test the old env variables OFFLINE and TAGGING that will
  160. // be deprecated by 1.10
  161. func trustCmdDeprecatedEnv(cmd *exec.Cmd, server, offlinePwd, taggingPwd string) {
  162. env := []string{
  163. "DOCKER_CONTENT_TRUST=1",
  164. fmt.Sprintf("DOCKER_CONTENT_TRUST_SERVER=%s", server),
  165. fmt.Sprintf("DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE=%s", offlinePwd),
  166. fmt.Sprintf("DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE=%s", taggingPwd),
  167. }
  168. cmd.Env = append(os.Environ(), env...)
  169. }
  170. func (s *DockerTrustSuite) setupTrustedImage(c *check.C, name string) string {
  171. repoName := fmt.Sprintf("%v/dockercli/%s:latest", privateRegistryURL, name)
  172. // tag the image and upload it to the private registry
  173. dockerCmd(c, "tag", "busybox", repoName)
  174. pushCmd := exec.Command(dockerBinary, "push", repoName)
  175. s.trustedCmd(pushCmd)
  176. out, _, err := runCommandWithOutput(pushCmd)
  177. if err != nil {
  178. c.Fatalf("Error running trusted push: %s\n%s", err, out)
  179. }
  180. if !strings.Contains(string(out), "Signing and pushing trust metadata") {
  181. c.Fatalf("Missing expected output on trusted push:\n%s", out)
  182. }
  183. if out, status := dockerCmd(c, "rmi", repoName); status != 0 {
  184. c.Fatalf("Error removing image %q\n%s", repoName, out)
  185. }
  186. return repoName
  187. }
  188. func notaryClientEnv(cmd *exec.Cmd, rootPwd, repositoryPwd string) {
  189. env := []string{
  190. fmt.Sprintf("NOTARY_ROOT_PASSPHRASE=%s", rootPwd),
  191. fmt.Sprintf("NOTARY_TARGETS_PASSPHRASE=%s", repositoryPwd),
  192. fmt.Sprintf("NOTARY_SNAPSHOT_PASSPHRASE=%s", repositoryPwd),
  193. }
  194. cmd.Env = append(os.Environ(), env...)
  195. }
  196. func (s *DockerTrustSuite) setupDelegations(c *check.C, repoName, pwd string) {
  197. initCmd := exec.Command(notaryClientBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "init", repoName)
  198. notaryClientEnv(initCmd, pwd, pwd)
  199. out, _, err := runCommandWithOutput(initCmd)
  200. if err != nil {
  201. c.Fatalf("Error initializing notary repository: %s\n", out)
  202. }
  203. // no command line for this, so build by hand
  204. nRepo, err := client.NewNotaryRepository(filepath.Join(cliconfig.ConfigDir(), "trust"), repoName, notaryURL, nil, passphrase.ConstantRetriever(pwd))
  205. if err != nil {
  206. c.Fatalf("Error creating notary repository: %s\n", err)
  207. }
  208. delgKey, err := nRepo.CryptoService.Create("targets/releases", data.ECDSAKey)
  209. if err != nil {
  210. c.Fatalf("Error creating delegation key: %s\n", err)
  211. }
  212. err = nRepo.AddDelegation("targets/releases", 1, []data.PublicKey{delgKey}, []string{""})
  213. if err != nil {
  214. c.Fatalf("Error creating delegation: %s\n", err)
  215. }
  216. // publishing first simulates the client pushing to a repo that they have been given delegated access to
  217. pubCmd := exec.Command(notaryClientBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "publish", repoName)
  218. notaryClientEnv(pubCmd, pwd, pwd)
  219. out, _, err = runCommandWithOutput(pubCmd)
  220. if err != nil {
  221. c.Fatalf("Error publishing notary repository: %s\n", out)
  222. }
  223. }