-
Notifications
You must be signed in to change notification settings - Fork 162
Remove JFS references + secrets engine injection #247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release/4.54
Are you sure you want to change the base?
Conversation
* cmd/secret: use new store Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> * Add temporary secrets engine client Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> * Lint fixes + remove tests + don't return cred value * update docs --------- Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Co-authored-by: Saurabh Davala <saurabh.davala@docker.com>
slimslenderslacks
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can merge this to a release/4.54 branch. But we can't merge this to main yet. No one outside docker can run this version of the gateway.
I'm also concerned that we're breaking compose file secrets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get rid of the entire backup package. It's superseded by profiles and secrets and now that the policy dump and set commands are gone, can we verify whether this entire package can be removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, I think we are safe to remove it. Could be another PR though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good, will address in a follow-up PR
pkg/mcp/remote.go
Outdated
| for _, secret := range c.config.Spec.Secrets { | ||
| env[secret.Env] = c.config.Secrets[secret.Name] | ||
| for _, s := range c.config.Spec.Secrets { | ||
| value := getSecretValue(ctx, s.Name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no err here. Don't need the value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to directly set
cmd/docker-mcp/commands/secret.go
Outdated
| } | ||
| flags := cmd.Flags() | ||
| flags.StringVar(&opts.Provider, "provider", "", "Supported: credstore, oauth/<provider>") | ||
| _ = flags.MarkDeprecated("provider", "option will be ignored") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there something we can say about how providers are now supported with "docker pass"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point - updated to say: all secrets now stored via docker pass in OS Keychain"
pkg/gateway/configuration.go
Outdated
| } | ||
| // Secrets no longer read during configuration load | ||
| // Instead, se:// URIs are passed to containers and resolved at runtime | ||
| secrets := make(map[string]string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be where we construct the se:// uris so that we do it in only one place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes added a helper method: buildSecretsURIs here
| if err != nil { | ||
| return Configuration{}, fmt.Errorf("reading MCP Toolkit's secrets: %w", err) | ||
| } | ||
| } else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this breaks some compose examples because we're not changing the --secrets options to the gateway yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, restored the: readSecretsFromFile flow. To verify I did the following locally:
- Created secrets.env file:
brave.api_key=your-brave-api-key
apify.api_key=your-apify-api-key
- Ran following command:
docker-mcp gateway run \
--secrets=secrets.env \
--servers=brave,apify \
--verbose
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! The only blocking thing is the chore (because it can cause bugs). I haven't been able to test it locally yet, but everything else in the code lgtm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, I think we are safe to remove it. Could be another PR though.
cmd/docker-mcp/commands/root.go
Outdated
| }, | ||
| Version: version.Version, | ||
| } | ||
| cmd.SetContext(ctx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: What was the reason for this change? Curious only because I'm pretty sure this cmd is different than the cmd inside of PersistentPreRunE. e.g. the one in that function is the actual subcommand that got run.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah good point, reverted this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah good point, reverted this
cmd/docker-mcp/commands/secret.go
Outdated
| ` | ||
|
|
||
| func secretCommand(docker docker.Client) *cobra.Command { | ||
| func secretCommand(_ docker.Client) *cobra.Command { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick (non-blocking): Could we just remove this param?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah no longer needed, removed
cmd/docker-mcp/commands/secret.go
Outdated
| Short: "Manage secrets", | ||
| Short: "Manage secrets in the local OS Keychain", | ||
| Example: strings.Trim(setSecretExample, "\n"), | ||
| PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chore: I unfortunately just learned the hard way that this can break things. See Slack thread.
I used an isSubcommandOf approach to work around this: https://github.com/docker/mcp-gateway/pull/266/files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see, thanks for calling that out. Updated to have:
// Note: Using PersistentPreRunE in secretCommand would override this parent hook
if isSubcommandOf(cmd, []string{"secret"}) {
if err := desktop.CheckHasDockerPass(cmd.Context()); err != nil {
return err
}
}
in: cmd/docker-mcp/commands/root.go
| } | ||
|
|
||
| return secretsByName, nil | ||
| func (c *WorkingSetConfiguration) readDockerDesktopSecrets(_ context.Context, _ []workingset.Server) (map[string]string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Does this mean we'll have some more cleanup after we merge this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, since with secrets engine we don't need to directly read secrets anymore, this is all dead code. I've removed this method all-together and instead we are returning se:// URI's for secrets as these are "injected" when starting up the container. Ex:
docker run -d -e POSTGRES_PASSWORD=se://docker/mcp/generic/postgres_password -p 5432 postgres
| // TODO: Remove once Secrets Engine fixes pattern matching bug | ||
| patterns := []string{ | ||
| fmt.Sprintf(`{"pattern": "%s*"}`, NamespaceGeneric), // Generic secrets (docker pass) | ||
| fmt.Sprintf(`{"pattern": "%s*"}`, NamespaceOAuth), // OAuth tokens | ||
| fmt.Sprintf(`{"pattern": "%s*"}`, NamespaceOAuthDCR), // DCR configs | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't been able to reproduce this. This won't match secrets that have nested namespaces, e.g. docker/mcp/generic/myapp/a-secret-key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, updated to have ** pattern for each type. Once we start getting all secrets when requesting docker/mcp/** will udpate
What I did
Changes
Secret Injection
Container MCPs
Secrets injected as
se://URIs, resolved by Docker Desktop at container runtime. Gateway never holds secret values in memory.Remote MCPs
Secrets queried from Secrets Engine and expanded into HTTP headers. Actual values required for Bearer tokens and header interpolation.
OAuth Tokens
OAuth tokens retrieved from Secrets Engine in Desktop mode. Falls back to credential helpers in CE mode. Token refresh monitoring also uses Secrets Engine.
Commands Removed
docker mcp policy set/dump- Policy management incompatible with Secrets Engine access controldocker mcp secret export- Replaced by Secrets Engine queriesCommands Changed
docker mcp secret setStores secrets via
docker passto OS Keychain underdocker/mcp/generic/namespace.docker mcp secret lsQueries Secrets Engine HTTP API instead of JFS socket. JSON output format compatible with Docker Desktop UI.
docker mcp secret rmDeletes secrets via
docker pass rm. Only removesdocker-passprovider secrets. Legacy secrets must be removed via OS credential tools.