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

Accept a slice of remote.Option for cosign verification #916

Merged
merged 2 commits into from
Sep 29, 2022

Conversation

souleb
Copy link
Member

@souleb souleb commented Sep 26, 2022

fixes #915

If implemented this enable passing a keychain, an authenticator and a custom transport as remote.Option to the verifier. It enables contextual login and self-signed certificates as well insecure registries.

Signed-off-by: Soule BA soule@weave.works

@souleb souleb marked this pull request as draft September 26, 2022 16:19
@souleb souleb marked this pull request as ready for review September 27, 2022 13:12
@souleb souleb marked this pull request as draft September 27, 2022 13:23
@souleb souleb force-pushed the fix-915 branch 3 times, most recently from d5854dc to 12e8230 Compare September 27, 2022 13:38
@stefanprodan
Copy link
Member

stefanprodan commented Sep 27, 2022

Tested d5854dc with a local registry and it fails to verify:

$ cosign verify --key=$HOME/.cosign/cosign.pub localhost:5050/podinfo-deploy:latest
Verification for localhost:5050/podinfo-deploy:latest --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key

[{"critical":{"identity":{"docker-reference":"localhost:5050/podinfo-deploy"},"image":{"docker-manifest-digest":"sha256:df41ceaea12823eb049ce7e4b80915bb59b8503b9a197accc93ae81b42b5962b"},"type":"cosign container image signature"},"optional":null}]

$ flux -n apps reconcile source oci podinfo-signed 
► annotating OCIRepository podinfo-signed in apps namespace
✔ OCIRepository annotated
◎ waiting for OCIRepository reconciliation
✗ OCIRepository reconciliation failed: 'failed to verify the signature using provider 'cosign': no matching signatures were found for 'kind-registry:5000/podinfo-deploy:latest''

If I disable verification, it works:

$ flux -n apps reconcile source oci podinfo-signed 
► annotating OCIRepository podinfo-signed in apps namespace
✔ OCIRepository annotated
◎ waiting for OCIRepository reconciliation
✔ fetched revision latest/df41ceaea12823eb049ce7e4b80915bb59b8503b9a197accc93ae81b42b5962b

Tested with:

apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
  name: podinfo-signed
  namespace: apps
spec:
  interval: 5m
  insecure: true
  url: oci://kind-registry:5000/podinfo-deploy #oci://ghcr.io/stefanprodan/podinfo-deploy
  ref:
    tag: latest
  verify:
    provider: cosign
    secretRef:
      name: podinfo-key
---
apiVersion: v1
kind: Secret
metadata:
  namespace: apps
  name: podinfo-key
stringData:
  key.pub: |
    -----BEGIN PUBLIC KEY-----
    MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEST+BqQ1XZhhVYx0YWQjdUJYIG5Lt
    iz2+UxRIqmKBqNmce2T+l45qyqOs99qfD7gLNGmkVZ4vtJ9bM7FxChFczg==
    -----END PUBLIC KEY-----

@darkowlzz
Copy link
Contributor

darkowlzz commented Sep 27, 2022

Key based verification works on azure with the latest commit (12e8230).

spec:
  interval: 1m0s
  provider: azure
  ref:
    tag: "1"
  timeout: 60s
  url: oci://xxxx.azurecr.io/hello-world
  verify:
    provider: cosign
    secretRef:
      name: cosign-public-keys
status:
  artifact:
    checksum: a159aec65b18430c32e9986deadbafc891e08f991974b9e2a07bd4700236d0de
    lastUpdateTime: "2022-09-27T13:45:36Z"
    path: ocirepository/default/hello-world/f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4.tar.gz
    revision: 1/f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4
    size: 2495
    url: http://source-controller.flux-system.svc.cluster.local./ocirepository/default/hello-world/f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4.tar.gz
  conditions:
  - lastTransitionTime: "2022-09-27T13:45:36Z"
    message: stored artifact for digest '1/f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4'
    observedGeneration: 1
    reason: Succeeded
    status: "True"
    type: Ready
  - lastTransitionTime: "2022-09-27T13:45:36Z"
    message: stored artifact for digest '1/f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4'
    observedGeneration: 1
    reason: Succeeded
    status: "True"
    type: ArtifactInStorage
  - lastTransitionTime: "2022-09-27T13:45:36Z"
    message: verified signature of revision 1/f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4
    observedGeneration: 1
    reason: Succeeded
    status: "True"
    type: SourceVerified
  observedGeneration: 1
  url: http://source-controller.flux-system.svc.cluster.local./ocirepository/default/hello-world/latest.tar.gz

Will try on GCP for keyless verification.

@darkowlzz
Copy link
Contributor

darkowlzz commented Sep 27, 2022

Tested d5854dc with a local registry and it fails to verify:

@stefanprodan I can also confirm that with the latest change, verification against local registry works. That commit had some issues. Please try the latest commit.
Update: My local registry is secured. Not sure about insecure registries.

@stefanprodan
Copy link
Member

stefanprodan commented Sep 27, 2022

@darkowlzz no luck with the latest commit, note that my registry has no auth at all, it's just a plain HTTP registry.

@stefanprodan stefanprodan added the area/oci OCI related issues and pull requests label Sep 27, 2022
@darkowlzz
Copy link
Contributor

darkowlzz commented Sep 27, 2022

Did more testing on GCP.
Key based verification just works, similar to the azure test posted above.
Keyless verification also works.

Followed the instructions from https://github.com/sigstore/cosign/blob/main/KEYLESS.md#on-gcp for signing.

Without signing the artifact, the following happens:

failed to verify the signature using provider 'cosign keyless': no matching signatures:

Signing the artifact without uploading the transparency log to rekor results in:

failed to verify the signature using provider 'cosign keyless': no matching signatures: signature not found in transparency log

Uploading the transparency log to rekor makes it work:

spec:
  interval: 1m0s
  provider: gcp
  ref:
    tag: "3"
  timeout: 60s
  url: oci://us-central1-docker.pkg.dev/xxxx/flux-test-moving-glowworm/hello-world
  verify:
    provider: cosign
status:
  artifact:
    checksum: 9f3bc0f341d4ecf2bab460cc59320a2a9ea292f01d7b96e32740a9abfd341088
    lastUpdateTime: "2022-09-27T15:20:48Z"
    path: ocirepository/default/hello-world/4c929c017d159e65154ddb38dae8d3edf54f911345d1453d1491b6a7bc1b28e9.tar.gz
    revision: 3/4c929c017d159e65154ddb38dae8d3edf54f911345d1453d1491b6a7bc1b28e9
    size: 1105
    url: http://source-controller.flux-system.svc.cluster.local/./ocirepository/default/hello-world/4c929c017d159e65154ddb38dae8d3edf54f911345d1453d1491b6a7bc1b28e9.tar.gz
  conditions:
  - lastTransitionTime: "2022-09-27T15:20:48Z"
    message: stored artifact for digest '3/4c929c017d159e65154ddb38dae8d3edf54f911345d1453d1491b6a7bc1b28e9'
    observedGeneration: 1
    reason: Succeeded
    status: "True"
    type: Ready
  - lastTransitionTime: "2022-09-27T15:20:48Z"
    message: stored artifact for digest '3/4c929c017d159e65154ddb38dae8d3edf54f911345d1453d1491b6a7bc1b28e9'
    observedGeneration: 1
    reason: Succeeded
    status: "True"
    type: ArtifactInStorage
  - lastTransitionTime: "2022-09-27T15:20:48Z"
    message: verified signature of revision 3/4c929c017d159e65154ddb38dae8d3edf54f911345d1453d1491b6a7bc1b28e9
    observedGeneration: 1
    reason: Succeeded
    status: "True"
    type: SourceVerified
  observedGeneration: 1
  url: http://source-controller.flux-system.svc.cluster.local/./ocirepository/default/hello-world/latest.tar.gz

@stefanprodan
Copy link
Member

stefanprodan commented Sep 27, 2022

I suspect the http transport gets overwritten by cosign and that's the reason spec.insecure doesn't work. @darkowlzz do you have a registry with a self-signed cert to test verify?

@darkowlzz
Copy link
Contributor

I suspect the whole transport gets overwritten by cosgin and that's the reason spec.insecure doesn't work. @darkowlzz do you have a registry with a self-signed cert to test verify?

@stefanprodan The latest commit may help https://github.com/fluxcd/source-controller/compare/12e8230b8e15131c28293951495e1e2122f8bd09..c8017244d28a8d8ea27b1d6a3fbb6187f44f761c .
My registry uses letsencrypt certs. But I think we use self-signed certs in our controller tests that need a local registry. Maybe we can make use of it?

@stefanprodan
Copy link
Member

stefanprodan commented Sep 27, 2022

The latest commit may help

@darkowlzz I've tested the last commit and it doesn't work with an insecure registry.

But I think we use self-signed certs in our controller tests that need a local registry. Maybe we can make use of it?

Yeap good idea, we need to add a separate test for client cert + cosign.

@stefanprodan
Copy link
Member

What's really annoying about all of this is that both crane and cosign are changing the transport when localhost is used, the tests are passing because of that, once you replace localhost with a Kubernetes service name, things fall apart.

@stefanprodan
Copy link
Member

Ok so the conclusion after many hours of head banging is that cosign doesn't propagate the insecure flag from their RegistryOptions to the name.Registry scheme, so it stays on HTTPS (when the host is not localhost), no relevant errors just no matching signatures were found 🤬

@souleb
Copy link
Member Author

souleb commented Sep 28, 2022

I have tested this on aws with contextual login and a given secret. The verification works as expected. Also tested with contextual login on gcp using a key and keyless verification.

@stefanprodan
Copy link
Member

@souleb let's fail the reconciliation if both verify and insecure are set with cosign does not support insecure registries.

options = append(options, crane.WithTransport(transport))
}

opts := r.makeOptions(ctx, obj, withTransport(transport), withKeychainOrAuth(keychain, auth))
Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't it be better to simply make the signature here makeOptions(ctx, obj, transport, keychain, auth) to prevent another options interface, and just have flat out conditional logic in makeOptions?

Copy link
Member Author

Choose a reason for hiding this comment

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

We will likely keep adding options (at least for insecure).

Copy link
Member Author

Choose a reason for hiding this comment

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

I have added a commit that complies with this.

@souleb
Copy link
Member Author

souleb commented Sep 29, 2022

While adding a test for cosign + registry with TLS, I discovered that the sign.SignCmd does not support passing custom transport... So I won't include that test case for now.

Copy link
Member

@stefanprodan stefanprodan left a comment

Choose a reason for hiding this comment

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

LGTM

Thanks @souleb 🏅

@hiddeco
Copy link
Member

hiddeco commented Sep 29, 2022

Think you can squash the last commit together with a866866.

Copy link
Member

@hiddeco hiddeco left a comment

Choose a reason for hiding this comment

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

Other than the nit, this looks good to me too but @darkowlzz might want to have another look.

Thanks @souleb 🙇

If implemented this enable passing a keychain, an authenticator and a
custom transport as remote.Option to the verifier. It enables contextual
login, self-signed certificates and insecure registries.

Signed-off-by: Soule BA <soule@weave.works>

refactor makeOptions

Reduce complexity by replacing the functional options with a flat out
conditional logic in makeOptions.

Signed-off-by: Soule BA <soule@weave.works>
If implemented we fails when trying to verify with insecure set. This
will likely change once cosign add support for insecure registries.

Signed-off-by: Soule BA <soule@weave.works>
Copy link
Contributor

@darkowlzz darkowlzz left a comment

Choose a reason for hiding this comment

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

LGTM!

@stefanprodan stefanprodan merged commit 2a2b525 into fluxcd:main Sep 29, 2022
@souleb souleb deleted the fix-915 branch September 29, 2022 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/oci OCI related issues and pull requests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

OCIRepository verification doesn't not support contextual login
4 participants