Commit graph

46 commits

Author SHA1 Message Date
Sebastiaan van Stijn
14503ccebd
api/server/middleware: NewVersionMiddleware: add validation
Make sure the middleware cannot be initialized with out of range versions.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 18:44:45 +01:00
Sebastiaan van Stijn
e1897cbde4
api/server/middleware:use API-consts in tests
Use the API consts to have more realistic values in tests.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 18:44:45 +01:00
Sebastiaan van Stijn
0fef6e1c99
api/server/middleware: VersionMiddleware: improve docs
Improve documentation and rename fields and variables to be more descriptive.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 18:44:45 +01:00
Sebastiaan van Stijn
cff4f20c44
migrate to github.com/containerd/log v0.1.0
The github.com/containerd/containerd/log package was moved to a separate
module, which will also be used by upcoming (patch) releases of containerd.

This patch moves our own uses of the package to use the new module.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-10-11 17:52:23 +02:00
Brian Goff
74da6a6363 Switch all logging to use containerd log pkg
This unifies our logging and allows us to propagate logging and trace
contexts together.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2023-06-24 00:23:44 +00:00
Sebastiaan van Stijn
f71fe8476a
api/server: fix empty-lines (revive)
api/server/router/build/build_routes.go:239:32: empty-lines: extra empty line at the start of a block (revive)
    api/server/middleware/version.go:45:241: empty-lines: extra empty line at the end of a block (revive)
    api/server/router/swarm/helpers_test.go:11:44: empty-lines: extra empty line at the end of a block (revive)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-09-28 01:58:51 +02:00
Sebastiaan van Stijn
857cb260c7
api: add const for 'X-Registry-Auth'
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-07-29 23:04:34 +02:00
Sebastiaan van Stijn
9f0b3f5609
bump gotest.tools v3.0.1 for compatibility with Go 1.14
full diff: https://github.com/gotestyourself/gotest.tools/compare/v2.3.0...v3.0.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2020-02-11 00:06:42 +01:00
Sebastiaan van Stijn
93100adb69
api/server: use constants for http methods
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-10-13 17:30:19 +02:00
Sebastiaan van Stijn
f8a0f26843 DebugRequestMiddleware: Remove path handling
Path-specific rules were removed, so this is no longer used.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 530e63c1a61b105a6f7fc143c5acb9b5cd87f958)
Signed-off-by: Tibor Vass <tibor@docker.com>
2019-07-09 21:42:12 +00:00
Sebastiaan van Stijn
73db8c77bf DebugRequestMiddleware: unconditionally scrub data field
Commit 77b8465d7e added a secret update
endpoint to allow updating labels on existing secrets. However, when
implementing the endpoint, the DebugRequestMiddleware was not updated
to scrub the Data field (as is being done when creating a secret).

When updating a secret (to set labels), the Data field should be either
`nil` (not set), or contain the same value as the existing secret. In
situations where the Data field is set, and the `dockerd` daemon is
running with debugging enabled / log-level debug, the base64-encoded
value of the secret is printed to the daemon logs.

The docker cli does not have a `docker secret update` command, but
when using `docker stack deploy`, the docker cli sends the secret
data both when _creating_ a stack, and when _updating_ a stack, thus
leaking the secret data if the daemon runs with debug enabled:

1. Start the daemon in debug-mode

        dockerd --debug

2. Initialize swarm

        docker swarm init

3. Create a file containing a secret

        echo secret > my_secret.txt

4. Create a docker-compose file using that secret

        cat > docker-compose.yml <<'EOF'
        version: "3.3"
        services:
          web:
            image: nginx:alpine
            secrets:
              - my_secret
        secrets:
          my_secret:
            file: ./my_secret.txt
        EOF

5. Deploy the stack

        docker stack deploy -c docker-compose.yml test

6. Verify that the secret is scrubbed in the daemon logs

        DEBU[2019-07-01T22:36:08.170617400Z] Calling POST /v1.30/secrets/create
        DEBU[2019-07-01T22:36:08.171364900Z] form data: {"Data":"*****","Labels":{"com.docker.stack.namespace":"test"},"Name":"test_my_secret"}

7. Re-deploy the stack to trigger an "update"

        docker stack deploy -c docker-compose.yml test

8. Notice that this time, the Data field is not scrubbed, and the base64-encoded secret is logged

        DEBU[2019-07-01T22:37:35.828819400Z] Calling POST /v1.30/secrets/w3hgvwpzl8yooq5ctnyp71v52/update?version=34
        DEBU[2019-07-01T22:37:35.829993700Z] form data: {"Data":"c2VjcmV0Cg==","Labels":{"com.docker.stack.namespace":"test"},"Name":"test_my_secret"}

This patch modifies `maskSecretKeys` to unconditionally scrub `Data` fields.
Currently, only the `secrets` and `configs` endpoints use a field with this
name, and no other POST API endpoints use a data field, so scrubbing this
field unconditionally will only scrub requests for those endpoints.

If a new endpoint is added in future where this field should not be scrubbed,
we can re-introduce more fine-grained (path-specific) handling.

This patch introduces some change in behavior:

- In addition to secrets, requests to create or update _configs_ will
  now have their `Data` field scrubbed. Generally, the actual data should
  not be interesting for debugging, so likely will not be problematic.
  In addition, scrubbing this data for configs may actually be desirable,
  because (even though they are not explicitely designed for this purpose)
  configs may contain sensitive data (credentials inside a configuration
  file, e.g.).
- Requests that send key/value pairs as a "map" and that contain a
  key named "data", will see the value of that field scrubbed. This
  means that (e.g.) setting a `label` named `data` on a config, will
  scrub/mask the value of that label.
- Note that this is already the case for any label named `jointoken`,
  `password`, `secret`, `signingcakey`, or `unlockkey`.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit c7ce4be93ae8edd2da62a588e01c67313a4aba0c)
Signed-off-by: Tibor Vass <tibor@docker.com>
2019-07-09 21:42:12 +00:00
Sebastiaan van Stijn
ebb542b3f8 TestMaskSecretKeys: use subtests
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 32d70c7e21631224674cd60021d3ec908c2d888c)
Signed-off-by: Tibor Vass <tibor@docker.com>
2019-07-09 21:42:12 +00:00
Sebastiaan van Stijn
18dac2cf32 TestMaskSecretKeys: add more test-cases
Add tests for

- case-insensitive matching of fields
- recursive masking

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit db5f811216e70bcb4a10e477c1558d6c68f618c5)
Signed-off-by: Tibor Vass <tibor@docker.com>
2019-07-09 21:42:12 +00:00
KimMachineGun
1377a2ddee api/server, dockerversion: modify context key
Signed-off-by: KimMachineGun <geon0250@gmail.com>
2018-08-22 11:20:22 +09:00
Vincent Demeester
3845728524
Update tests to use gotest.tools 👼
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2018-06-13 09:04:30 +02:00
Kir Kolyshkin
7d62e40f7e Switch from x/net/context -> context
Since Go 1.7, context is a standard package. Since Go 1.9, everything
that is provided by "x/net/context" is a couple of type aliases to
types in "context".

Many vendored packages still use x/net/context, so vendor entry remains
for now.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2018-04-23 13:52:44 -07:00
Daniel Nephin
6be0f70983 Automated migration using
gty-migrate-from-testify --ignore-build-tags

Signed-off-by: Daniel Nephin <dnephin@docker.com>
2018-03-16 11:03:43 -04:00
Daniel Nephin
4f0d95fa6e Add canonical import comment
Signed-off-by: Daniel Nephin <dnephin@docker.com>
2018-02-05 16:51:57 -05:00
Vincent Demeester
fbed4eb8c7
Merge pull request #36013 from thaJeztah/improve-version-middleware-test
Improve API version-middleware test
2018-01-22 14:59:06 -08:00
Sebastiaan van Stijn
dfac74a9e4
Golint: don't use basic untyped string for context key
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-01-15 12:49:14 +01:00
Sebastiaan van Stijn
63906d8fae
Improve API version-middleware test
Some improvements to the test;

- Combine tests to reduce duplicated code
- Add test-cases for empty version in request using the default version
- Add test for valid versions in request actually setting the version

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-01-15 11:50:30 +01:00
Sebastiaan van Stijn
e9dac5ef5e
Always return version and server headers
If a 400 error is returned due to an API version mismatch, no
version and server-identification headers were returned by the API.

All information in these headers is "static", so there is no
reason to omit the information in case of an error being
returned.

This patch updates the version middleware to always
return the headers.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2017-10-11 22:06:43 +02:00
Sebastiaan van Stijn
01f9227ec9
Return 400 error if API client is too new
Commit e98e4a7111 implemented API version
negotiation using the `/_ping` endpoint. In that change, URL validation for the
maximum supported API version was removed from the API server (validation for
the _minimum_ version was kept in place).

With this feature, clients that support version negotiation would negotiate the
maximum version supported by the daemon, and downgrade to an older API version
if the client's default API version is not supported.

However, clients that do _not_ support version negotiation can call API versions
that are higher than the maximum supported version. Due to the missing version
check, this is silently ignored, and the daemon's default API version is used.

This is a problem, because the actual API version in use is non-deterministic;
for example, calling `/v9999.9999/version` on a daemon that runs API v1.34 will
use API v1.34, but calling the same URL on an older daemon may use API version
v1.24.

This patch reverts the removal of the API check for maximum supported versions.
The documentation has been updated accordingly

Before this patch is applied, the daemon returns a 200 (success):

    $ curl -v --unix-socket /var/run/docker.sock http://localhost/v9999.9999/version
    *   Trying /var/run/docker.sock...
    * Connected to localhost (/Users/sebastiaan/Library/Containers/com.dock) port 80 (#0)
    > GET /v9999.9999/version HTTP/1.1
    > Host: localhost
    > User-Agent: curl/7.54.0
    > Accept: */*
    >
    < HTTP/1.1 200 OK
    < Api-Version: 1.32
    < Content-Length: 240
    < Content-Type: application/json
    < Date: Tue, 10 Oct 2017 09:11:29 GMT
    < Docker-Experimental: true
    < Ostype: linux
    < Server: Docker/17.09.0-ce (linux)
    <
    {"Version":"17.09.0-ce","ApiVersion":"1.32","MinAPIVersion":"1.12","GitCommit":"afdb6d4","GoVersion":"go1.8.3","Os":"linux","Arch":"amd64","KernelVersion":"4.9.49-moby","Experimental":true,"BuildTime":"2017-09-26T22:45:38.000000000+00:00"}
    * Connection #0 to host localhost left intact

After this patch is applied, a 400 (Bad Request) is returned:

    $ curl -v --unix-socket /var/run/docker.sock http://localhost/v9999.9999/version
    *   Trying /var/run/docker.sock...
    * Connected to localhost (/var/run/docker.sock) port 80 (#0)
    > GET /v9999.9999/info HTTP/1.1
    > Host: localhost
    > User-Agent: curl/7.52.1
    > Accept: */*
    >
    < HTTP/1.1 400 Bad Request
    < Content-Type: application/json
    < Date: Tue, 10 Oct 2017 08:08:34 GMT
    < Content-Length: 89
    <
    {"message":"client version 9999.9999 is too new. Maximim supported API version is 1.34"}
    * Curl_http_done: called premature == 0
    * Connection #0 to host localhost left intact

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2017-10-10 11:17:48 +02:00
Daniel Nephin
9b47b7b151 Fix golint errors.
Signed-off-by: Daniel Nephin <dnephin@docker.com>
2017-08-18 14:23:44 -04:00
Brian Goff
ebcb7d6b40 Remove string checking in API error handling
Use strongly typed errors to set HTTP status codes.
Error interfaces are defined in the api/errors package and errors
returned from controllers are checked against these interfaces.

Errors can be wraeped in a pkg/errors.Causer, as long as somewhere in the
line of causes one of the interfaces is implemented. The special error
interfaces take precedence over Causer, meaning if both Causer and one
of the new error interfaces are implemented, the Causer is not
traversed.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2017-08-15 16:01:11 -04:00
Derek McGowan
1009e6a40b
Update logrus to v1.0.1
Fixes case sensitivity issue

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
2017-07-31 13:16:46 -07:00
Aaron Lehmann
3fbc352cbb middleware: Redact secret data on "secret create"
With debug logging turned on, we currently log the base64-encoded secret
payload.

Change the middleware code to redact this. Since the field is called
"Data", it requires some context-sensitivity. The URI path is examined
to see which route is being invoked.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2017-06-29 16:04:47 -07:00
Ying Li
d60f182049 Do not log the CA config CA signing key in debug mode.
Signed-off-by: Ying Li <ying.li@docker.com>
2017-05-31 18:15:33 -07:00
Boaz Shuster
7199522ea2 Hide command options that are related to Windows
Signed-off-by: Boaz Shuster <ripcurld.github@gmail.com>
2017-03-12 08:47:17 +02:00
fate-grand-order
2a8d6368d4 use t.Fatal() to output the err message where the values used for formatting
text does not appear to contain a placeholder

Signed-off-by: Helen Xie <chenjg@harmonycloud.cn>
2017-02-23 10:16:22 +08:00
Aaron Lehmann
0f9fc54df9 Revise swarm init/update flags, add unlocking capability
- Neither swarm init or swarm update should take an unlock key
- Add an autolock flag to turn on autolock
- Make the necessary docker api changes
- Add SwarmGetUnlockKey API call and use it when turning on autolock
- Add swarm unlock-key subcommand

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-11-09 16:09:00 -08:00
Tonis Tiigi
b4a667c8c4 Add support for swarm init lock and swarm unlock
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2016-11-09 16:09:00 -08:00
Victor Vieux
e98e4a7111 always add but hide experimental cmds and flags
Signed-off-by: Victor Vieux <vieux@docker.com>

update cobra and use Tags

Signed-off-by: Victor Vieux <vieux@docker.com>

allow client to talk to an older server

Signed-off-by: Victor Vieux <vieux@docker.com>
2016-11-08 04:55:27 -08:00
Kenfe-Mickael Laventure
7781a1bf0f Make experimental a runtime flag
Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
2016-10-24 15:20:01 -07:00
Daniel Nephin
bcb0405239 Use apiError in server version middleware.
Signed-off-by: Daniel Nephin <dnephin@docker.com>
2016-09-16 12:27:14 -04:00
Michael Crosby
91e197d614 Add engine-api types to docker
This moves the types for the `engine-api` repo to the existing types
package.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2016-09-07 11:05:58 -07:00
Tonis Tiigi
e3917c76ce Mask join tokens in daemon logs
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2016-08-02 15:15:23 -07:00
Tonis Tiigi
8b8f86aec9 Mask swarm secrets from daemon logs
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2016-06-30 17:11:09 -07:00
Vincent Demeester
7534f17261
Update code for latest engine-api
- Update CopyToContainer uses
- Use engine-api/types/versions instead of pkg/version

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2016-04-19 16:56:54 +02:00
David Calavera
8d3467626e
Move middleware to interfaces.
This makes separating middlewares from the core api easier.
As an example, the authorization middleware is moved to
it's own package.

Initialize all static middlewares when the server is created, reducing
allocations every time a route is wrapper with the middlewares.

Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-04-11 09:19:27 -07:00
Liron Levin
3c157713b3 Extend Docker authorization with TLS user information
Currently Docker authorization framework does not use any user
information, which already available in the Docker context for TLS
connection.
The purpose of this CR is to complete the existing authz work by adding
the basic client certificate details (SUBJECT_NAME) and authentication
method (TLS) to the authz request.

We think this should be the default behavior when no extended
authorization module is specified (currently WIP under #20883).

Signed-off-by: Liron Levin <liron@twistlock.com>
2016-03-27 15:53:55 +03:00
Mike Goelzer
d1502afb63 Pass upstream client's user agent through to registry on image pulls
Changes how the Engine interacts with Registry servers on image pull.
Previously, Engine sent a User-Agent string to the Registry server
that included only the Engine's version information.  This commit
appends to that string the fields from the User-Agent sent by the
client (e.g., Compose) of the Engine.  This allows Registry server
operators to understand what tools are actually generating pulls on
their registries.

Signed-off-by: Mike Goelzer <mgoelzer@docker.com>
2016-03-20 04:30:09 -07:00
Antonio Murdaca
526ddd3512 api: server: server: remove redunant debugf
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
2016-03-07 09:03:29 +01:00
allencloud
2736f77a94 fix typos
Signed-off-by: allencloud <allen.sun@daocloud.io>
2016-03-06 00:59:11 +08:00
David Calavera
a793564b25 Remove static errors from errors package.
Moving all strings to the errors package wasn't a good idea after all.

Our custom implementation of Go errors predates everything that's nice
and good about working with errors in Go. Take as an example what we
have to do to get an error message:

```go
func GetErrorMessage(err error) string {
	switch err.(type) {
	case errcode.Error:
		e, _ := err.(errcode.Error)
		return e.Message

	case errcode.ErrorCode:
		ec, _ := err.(errcode.ErrorCode)
		return ec.Message()

	default:
		return err.Error()
	}
}
```

This goes against every good practice for Go development. The language already provides a simple, intuitive and standard way to get error messages, that is calling the `Error()` method from an error. Reinventing the error interface is a mistake.

Our custom implementation also makes very hard to reason about errors, another nice thing about Go. I found several (>10) error declarations that we don't use anywhere. This is a clear sign about how little we know about the errors we return. I also found several error usages where the number of arguments was different than the parameters declared in the error, another clear example of how difficult is to reason about errors.

Moreover, our custom implementation didn't really make easier for people to return custom HTTP status code depending on the errors. Again, it's hard to reason about when to set custom codes and how. Take an example what we have to do to extract the message and status code from an error before returning a response from the API:

```go
	switch err.(type) {
	case errcode.ErrorCode:
		daError, _ := err.(errcode.ErrorCode)
		statusCode = daError.Descriptor().HTTPStatusCode
		errMsg = daError.Message()

	case errcode.Error:
		// For reference, if you're looking for a particular error
		// then you can do something like :
		//   import ( derr "github.com/docker/docker/errors" )
		//   if daError.ErrorCode() == derr.ErrorCodeNoSuchContainer { ... }

		daError, _ := err.(errcode.Error)
		statusCode = daError.ErrorCode().Descriptor().HTTPStatusCode
		errMsg = daError.Message

	default:
		// This part of will be removed once we've
		// converted everything over to use the errcode package

		// FIXME: this is brittle and should not be necessary.
		// If we need to differentiate between different possible error types,
		// we should create appropriate error types with clearly defined meaning
		errStr := strings.ToLower(err.Error())
		for keyword, status := range map[string]int{
			"not found":             http.StatusNotFound,
			"no such":               http.StatusNotFound,
			"bad parameter":         http.StatusBadRequest,
			"conflict":              http.StatusConflict,
			"impossible":            http.StatusNotAcceptable,
			"wrong login/password":  http.StatusUnauthorized,
			"hasn't been activated": http.StatusForbidden,
		} {
			if strings.Contains(errStr, keyword) {
				statusCode = status
				break
			}
		}
	}
```

You can notice two things in that code:

1. We have to explain how errors work, because our implementation goes against how easy to use Go errors are.
2. At no moment we arrived to remove that `switch` statement that was the original reason to use our custom implementation.

This change removes all our status errors from the errors package and puts them back in their specific contexts.
IT puts the messages back with their contexts. That way, we know right away when errors used and how to generate their messages.
It uses custom interfaces to reason about errors. Errors that need to response with a custom status code MUST implementent this simple interface:

```go
type errorWithStatus interface {
	HTTPErrorStatusCode() int
}
```

This interface is very straightforward to implement. It also preserves Go errors real behavior, getting the message is as simple as using the `Error()` method.

I included helper functions to generate errors that use custom status code in `errors/errors.go`.

By doing this, we remove the hard dependency we have eeverywhere to our custom errors package. Yes, you can use it as a helper to generate error, but it's still very easy to generate errors without it.

Please, read this fantastic blog post about errors in Go: http://dave.cheney.net/2014/12/24/inspecting-errors

Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-02-26 15:49:09 -05:00
David Calavera
1ba44a832f Make server middleware standalone functions.
Removing direct dependencies from the server configuration.

Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-02-24 14:48:52 -05:00