Skip to content
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

Add encryption decryption feature #16329

Merged

Conversation

gupttaru
Copy link
Contributor

@gupttaru gupttaru commented Oct 28, 2022

This PR adds encryption decryption functionality, just like those present in buildah and skopeo. containers/common/libimage already supports encryption-decryption of images, so its a Podman only change.

This would allow us to encrypt the image while pushing it to a registry and decrypt the image while pulling it from a registry.

The commands would be as follows:

podman push --encryption-key protocol:keyfile IMAGE
podman pull --decyrption-key protocol:keyfile IMAGE 

Additionally,

podman run --decryption-key <key> IMAGE [command [arg …]]
would automatically pull the image from a registry, decrypt it using decryption key and run the container.

Signed-off-by: Tarun Gupta [email protected]

Does this PR introduce a user-facing change?

Yes.

This PR adds the flag `--encryption-key` and `--encrypt-layer` to the push command, and `--decryption-key` to pull and run command.

@openshift-ci openshift-ci bot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. release-note labels Oct 28, 2022
@gupttaru gupttaru force-pushed the encryption-decryption-feature branch from e778c76 to 01ba20f Compare October 28, 2022 07:28
"*Experimental* key needed to decrypt the image (e.g. /path/to/key.pem)",
)
_ = cmd.RegisterFlagCompletionFunc(annotationFlagName, completion.AutocompleteNone)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this blank line to make linter happy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@rhatdan
Copy link
Member

rhatdan commented Oct 28, 2022

I am fine with this.

podman build --decryption-key is already supported.

createFlags.StringSliceVar(
&cf.DecryptionKeys,
decryptionKeysFlagName, []string{},
"*Experimental* key needed to decrypt the image (e.g. /path/to/key.pem)",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this Experimental? It is not in Buildah?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed "Experimental"

@@ -107,6 +108,9 @@ func pullFlags(cmd *cobra.Command) {
flags.StringVar(&pullOptions.Authfile, authfileFlagName, auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
_ = cmd.RegisterFlagCompletionFunc(authfileFlagName, completion.AutocompleteDefault)

decryptionKeysFlagName := "decryption-key"
flags.StringSliceVar(&pullOptions.DecryptionKeys, decryptionKeysFlagName, nil, "*Experimental* key needed to decrypt the image (e.g. /path/to/key.pem)")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove "Experimental"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -121,6 +124,14 @@ func pushFlags(cmd *cobra.Command) {
flags.StringVar(&pushOptions.CompressionFormat, compressionFormat, "", "compression format to use")
_ = cmd.RegisterFlagCompletionFunc(compressionFormat, common.AutocompleteCompressionFormat)

encryptionKeysFlagName := "encryption-key"
flags.StringSliceVar(&pushOptions.EncryptionKeys, encryptionKeysFlagName, nil, "*Experimental* key with the encryption protocol to use needed to encrypt the image (e.g. jwe:/path/to/key.pem)")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove Experimental

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

_ = cmd.RegisterFlagCompletionFunc(encryptionKeysFlagName, completion.AutocompleteDefault)

encryptLayersFlagName := "encrypt-layer"
flags.IntSliceVar(&pushOptions.EncryptLayers, encryptLayersFlagName, nil, "*Experimental* layers to encrypt, 0-indexed layer indices with support for negative indexing (e.g. 0 is the first layer, -1 is the last layer). If not defined, will encrypt all layers if encryption-key flag is specified")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove Experimental

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@rhatdan
Copy link
Member

rhatdan commented Oct 28, 2022

Needs tests.

@rhatdan
Copy link
Member

rhatdan commented Oct 28, 2022

Overall @gupttaru this looks good, thanks.

Copy link
Contributor Author

@gupttaru gupttaru left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed comments by @rhatdan , and added tests

createFlags.StringSliceVar(
&cf.DecryptionKeys,
decryptionKeysFlagName, []string{},
"*Experimental* key needed to decrypt the image (e.g. /path/to/key.pem)",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed "Experimental"

"*Experimental* key needed to decrypt the image (e.g. /path/to/key.pem)",
)
_ = cmd.RegisterFlagCompletionFunc(annotationFlagName, completion.AutocompleteNone)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@@ -107,6 +108,9 @@ func pullFlags(cmd *cobra.Command) {
flags.StringVar(&pullOptions.Authfile, authfileFlagName, auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
_ = cmd.RegisterFlagCompletionFunc(authfileFlagName, completion.AutocompleteDefault)

decryptionKeysFlagName := "decryption-key"
flags.StringSliceVar(&pullOptions.DecryptionKeys, decryptionKeysFlagName, nil, "*Experimental* key needed to decrypt the image (e.g. /path/to/key.pem)")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -121,6 +124,14 @@ func pushFlags(cmd *cobra.Command) {
flags.StringVar(&pushOptions.CompressionFormat, compressionFormat, "", "compression format to use")
_ = cmd.RegisterFlagCompletionFunc(compressionFormat, common.AutocompleteCompressionFormat)

encryptionKeysFlagName := "encryption-key"
flags.StringSliceVar(&pushOptions.EncryptionKeys, encryptionKeysFlagName, nil, "*Experimental* key with the encryption protocol to use needed to encrypt the image (e.g. jwe:/path/to/key.pem)")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

_ = cmd.RegisterFlagCompletionFunc(encryptionKeysFlagName, completion.AutocompleteDefault)

encryptLayersFlagName := "encrypt-layer"
flags.IntSliceVar(&pushOptions.EncryptLayers, encryptLayersFlagName, nil, "*Experimental* layers to encrypt, 0-indexed layer indices with support for negative indexing (e.g. 0 is the first layer, -1 is the last layer). If not defined, will encrypt all layers if encryption-key flag is specified")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@gupttaru gupttaru force-pushed the encryption-decryption-feature branch from bd272da to c942994 Compare November 10, 2022 11:10
@gupttaru
Copy link
Contributor Author

In the Cirrus CI pipeline, some of the tests related to things I haven't touched are failing:

[+1357s] [Fail] Podman search [It] podman search format json list tags 
[+1357s] /var/tmp/go/src/github.com/containers/podman/test/e2e/search_test.go:137

[+1513s] [Fail] Podman run networking [It] podman do not tamper with joined network ns interfaces 
[+1513s] /var/tmp/go/src/github.com/containers/podman/test/e2e/run_networking_test.go:834

[+1513s] [Fail] Podman create with --ip flag [It] Podman create with specified static IP has correct IP 
[+1513s] /var/tmp/go/src/github.com/containers/podman/test/e2e/create_staticip_test.go:75

[+1469s] [Fail] Podman search [It] podman search format json list tags 
[+1469s] /var/tmp/go/src/github.com/containers/podman/test/e2e/search_test.go:1

Could someone help with the above errors?

Also the tests I have added for checking the encryption-decryption feature are passing except one: podman-remote is able to pull encrypted image without providing decryption key (link to CI logs). So the following is NOT throwing an error:

# podman-remote [options] run -d --name registry -p 5000:5000 quay.io/libpod/registry:2.8 /entrypoint.sh /etc/docker/registry/config.yml
# podman-remote [options] push --encryption-key jwe:/tmp/podman_test2360113671/key.rsa.pub --tls-verify=false --remove-signatures quay.io/libpod/alpine:latest localhost:5000/my-alpine
# podman-remote [options] rmi quay.io/libpod/alpine:latest
# podman-remote [options] pull localhost:5000/my-alpine

I am unable to at the moment exactly find the reason for this. Trying to debug this at the moment.

@gupttaru gupttaru requested a review from rhatdan November 11, 2022 14:36
@rhatdan rhatdan marked this pull request as ready for review November 11, 2022 15:44
@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Nov 11, 2022
@rhatdan
Copy link
Member

rhatdan commented Nov 11, 2022

First can you squash your commits

git rebase -i origin
git push --force

@mtrmac @vrothberg PTAL

Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK to the non-test code, based on a fairly cursory skim.

podman-remote is able to pull encrypted image without providing decryption key

That sounds like a blocker for now. It might not be a bug at all, but it does need to be understood, so that we are certain we are not publishing unencrypted images when the user asks for encrypted. (OTOH I didn’t now read any part of the tests — this is admittedly just an emphasis of the known without contributing anything new.)

@gupttaru gupttaru force-pushed the encryption-decryption-feature branch from abd03e1 to c284455 Compare November 14, 2022 05:43
@gupttaru
Copy link
Contributor Author

It might not be a bug at all, but it does need to be understood, so that we are certain we are not publishing unencrypted images when the user asks for encrypted.

Most probably there might be a problem with test code (link), which might be pushing unencrypted images somehow, even though I am passing the --encryption-key flag. Though I am unable to exactly see why this problem is occurring only in podman-remote, and not podman.

Also, what could be the reason for failing of other unit-tests not related to this added feature, as mentioned above?

@mtrmac
Copy link
Collaborator

mtrmac commented Nov 14, 2022

> which might be pushing unencrypted images somehow… I am unable to exactly see why this problem is occurring only in podman-remote,

I can’t see any new fields added in pkg/bindings, so my first guess is that the RPC to pass options to the remote server is simply missing in this PR. (But I’m only slightly familiar with how the remote mode works.)

Does it even make sense to support this on remote? Compare #15163 (comment) . (But if it is not supported, the request to push with encryption must fail instead of pushing without encryption.)

@rhatdan
Copy link
Member

rhatdan commented Nov 14, 2022

Yes you need to change pkg/api and maybe pkg/bindings to pass the option accross the protocol to the server.

@gupttaru
Copy link
Contributor Author

Yes you need to change pkg/api and maybe pkg/bindings to pass the option accross the protocol to the server.

Thanks, I am not well acquainted with the podman-remote mode, so missed this.

Does it even make sense to support this on remote? Compare #15163 (comment) . (But if it is not supported, the request to push with encryption must fail instead of pushing without encryption.)

I do agree with this comment. Sending the key over a protocol would be risky. The keys are usually made available on the machine which is pushing/pulling the image, in a secure manner, using some KMS (Key Management Service) or some Secret Manager. For example: Ocicrypt keyprovider protocol allows using a KMS for providing keys in a secure manner.

Similar to other flags which are not supported on podman-remote, I think we could hide the encryption related flags for remote mode, for example as done here. If we hide the flag for remote mode, I don't think we would need any changes in pkg/api and pkg/bindings

@mtrmac
Copy link
Collaborator

mtrmac commented Nov 15, 2022

I’d still like to see code in the remote client that makes sure that request fails: a field in pkg/domains/entities that is silently ignored is a time bomb otherwise.

Admittedly we apparently don’t do that in other cases, like --sign-by; we probably should. The failure case with ignoring the --encryption-key option is so much worse, though, that this is much more important to do for that option.

@rhatdan
Copy link
Member

rhatdan commented Nov 15, 2022

SGTM
Reject these commands in remote mode. BTW This means they would not be able to be used on MAC and Windows platforms.
You can make podman-remote throw an error when using any of these options, including --sign-by.
The man pages should reflect that these are not supported for Remote as well.

@gupttaru
Copy link
Contributor Author

Admittedly we apparently don’t do that in other cases, like --sign-by; we probably should. The failure case with ignoring the --encryption-key option is so much worse

You can make podman-remote throw an error when using any of these options, including --sign-by.

Given that we need to make this change for all the options that are not supported by podman-remote (--sign-by, --encryption-key etc.) can we make that a part of a separate issue/PR? For now, I can make the encryption-key flag conform with how other flags are treated. Admittedly, currently I am not well acquainted with the remote side of Podman, and not sure how this change would look.

@rhatdan
Copy link
Member

rhatdan commented Nov 17, 2022

Yes we can fix the others in a different commit, but for now you have to fix the new options to not run tests in remote mode.

@mtrmac
Copy link
Collaborator

mtrmac commented Nov 17, 2022

For now, I can make the encryption-key flag conform with how other flags are treated.

I think the encryption-key flag must cause an error at the API level (not just the CLI), as part of this PR. The consequences of silently ignoring it are materially worse than the others.

@gupttaru gupttaru force-pushed the encryption-decryption-feature branch from c284455 to a8680b6 Compare November 17, 2022 13:39
@gupttaru gupttaru force-pushed the encryption-decryption-feature branch from a8680b6 to 613789a Compare November 17, 2022 13:43
@gupttaru
Copy link
Contributor Author

I think the encryption-key flag must cause an error at the API level (not just the CLI), as part of this PR.

Understood.

Based on my current understanding of API code of Podman, this change would involve defining a query parameter for encryption-key in Podman libpod API's PushImage function (here), and then if the encryption-key is actually passed as a query parameter by the user, then raising an error.

Likewise, defining query parameters for options encrypt-layer and decryption-key, and then raising errors from libpod's API's functions PushImage and ImagesPull.

So these would only involve changes in files pkg/api/handlers/libpod/{images_push,images_pull}.go

I couldn't think of any changes in pkg/bindings/images/{push,pull}.go

@mtrmac
Copy link
Collaborator

mtrmac commented Nov 21, 2022

If you want to do all the work to add an actual query parameter to the HTTP API, send it and parse it, you might just as well hook it up right through to the actual server implementation (but, per the other discussion, I’m not sure that would actually work at all).

Instead, just modify the client binary; the PR adds fields to pkg/domain/entities.ImagePushOptions, so all consumers of that struct should either implement the new fields or reject it. E.g. https://github.com/gupttaru/podman/blob/613789a9e5eace8e005fbddd1e2ca7ac2a818ed1/pkg/domain/infra/tunnel/images.go#L242 needs to check for the new fields, and fail if they are set.

If we don’t add the field to the HTTP API, the pkg/bindings clients to the HTTP API will remain unaffected, because there would be no new field to reject.


(The package names are very confusing to me. I’m increasingly tempted to recommend renaming to pkg/http/server, pkg/http/client, pkg/engine/local, pkg/engine/remote, even with all the churn that would cause.)

@gupttaru gupttaru force-pushed the encryption-decryption-feature branch from 613789a to 788c486 Compare November 22, 2022 05:59
@gupttaru
Copy link
Contributor Author

Thanks @mtrmac for your help.

I have made the requisite changes in /pkg/domain/infra/tunnel/images.go to raise an error if the encryption or decryption related variables are set. You can see these changes here and here.

The package names are very confusing to me

I also find them quite confusing because of which I was finding it hard to understand the changes requried which you mentioned above. Would it be possible add a small README.md file for such folders to explain what they do? For example, I don't know the full-form of abi in pkg/domain/infra/abi; nor was it very clear to me that the tunnel folder would be handling the remote client related things. A small README.md (similar to what we have for pkg/bindings) would be quite helpful for future open-source collaborators I believe.

Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

The implementation seems reasonable. (I didn’t review the tests in detail.)

I’ll leave the final approval to actual Podman maintainers.

test/e2e/common_test.go Outdated Show resolved Hide resolved
Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much for me reviewing…

The tests show actual failures that need fixing.

pkg/util/utils.go Outdated Show resolved Hide resolved
@gupttaru gupttaru force-pushed the encryption-decryption-feature branch from 788c486 to 5822e39 Compare November 24, 2022 07:29
@gupttaru gupttaru force-pushed the encryption-decryption-feature branch from 5822e39 to 3bb9ed4 Compare November 24, 2022 09:56
@gupttaru
Copy link
Contributor Author

Thanks @mtrmac. The tests are passing now.

@rhatdan
Copy link
Member

rhatdan commented Nov 28, 2022

/approve
/lgtm
Thanks @gupttaru

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Nov 28, 2022
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Nov 28, 2022

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: gupttaru, rhatdan

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Nov 28, 2022
@openshift-merge-robot openshift-merge-robot merged commit c1db4f8 into containers:main Nov 28, 2022
@github-actions github-actions bot added the locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments. label Sep 20, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments. release-note
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants