Skip to content

feat: Provide credentials in imagePullSecret without global access#2161

Merged
simar7 merged 8 commits intoaquasecurity:mainfrom
maltemorgenstern:2158-private-images-without-global-access
Jun 9, 2025
Merged

feat: Provide credentials in imagePullSecret without global access#2161
simar7 merged 8 commits intoaquasecurity:mainfrom
maltemorgenstern:2158-private-images-without-global-access

Conversation

@maltemorgenstern
Copy link
Copy Markdown
Contributor

Description

When running a cluster that contains images from a private registry one needs to configure authentication. This is done by using kubernetes ImagePullSecrets. By default the trivy-operator is able to read the secrets attached to a target workload and use them to access the container registry.

While this is necessary when working with different registries inside the cluster, this comes with one security downside: the operator needs access to all secrets inside the cluster.

If all images are being pulled from a single private registry then one ImagePullSecret can be used for all of them. The easiest one to use is inside the operator namespace (because the operator has access to secrets in its own namespace).

This change does not impact any deployments running with default settings (global access enabled). But in case one disables that access this allows to instead read a single ImagePullSecret and use it for all images.

Related issues

Checklist

  • I've read the guidelines for contributing to this repository.
  • I've added tests that prove my fix is effective or that my feature works.
  • I've updated the documentation with the relevant information (if needed).
  • I've added usage information (if the PR introduces new options)
  • I've included a "before" and "after" example to the description (if the PR is a user interface change).

When running a cluster that contains images from a private registry one
needs to configure authentication. This is done by using kubernetes
ImagePullSecrets. By default the trivy-operator is able to read the
secrets attached to a target workload and use them to access the
container registry.

While this is necessary when working with different registries inside
the cluster, this comes with one security downside: the operator needs
access to all secrets inside the cluster.

If all images are being pulled from a single private registry then
one ImagePullSecret can be used for all of them. The easiest one to
use is inside the operator namespace.

This change does not impact any deployments running with default
settings (global access enabled). But in case one disables that
access this allows to instead read a single ImagePullSecret and
use it for all images.
@maltemorgenstern maltemorgenstern marked this pull request as draft June 27, 2024 20:04
@maltemorgenstern
Copy link
Copy Markdown
Contributor Author

Hey, this MR is not finished (and tests will fail for sure), but I wanted to get your opinion on my approach first - afterwards, I will try to add and fix the necessary tests.

operator:
  accessGlobalSecretsAndServiceAccount: false
  privateRegistryScanSecretsNames: {"trivy-operator":"internal-pullsecret"}

With this change the above configuration would allow the trivy-operator to pull all images inside the cluster that use the same private registry - while not having to grant it access to every secret in the entire cluster.

WDYT?

@chen-keinan
Copy link
Copy Markdown
Contributor

@maltemorgenstern looks ok in general

The unit tests have been fixed and now cover three different scenarios:
- No credentials have been configured at all
- ImagePullSecret for workload exists but global access is disabled
- ImagePullSecret for workload exists and global access is enabled

Also a small typo in the CONTRIBUTING.md is being fixed.
In [1] the trivy-operator updates the temporary secrets to reflect the ownership by
each scan job. This requires the 'update' persmission for secrets - otherwise the
call with result in an error ("forbidden").

While the ClusterRole has this permission the Role does not. This needs to be added
to run the trivy-operator without global access - while still using imagePullSecrets
to configure authentication for private registries.

[1]: https://github.com/aquasecurity/trivy-operator/blob/d5d7e3d25c5e98f92c6a596af639b1f8df721869/pkg/vulnerabilityreport/controller/workload.go#L380-L389
@maltemorgenstern maltemorgenstern marked this pull request as ready for review July 21, 2024 18:12
@maltemorgenstern
Copy link
Copy Markdown
Contributor Author

Hey @chen-keinan, I finally found the time to finalize this PR - it's ready for review now.

FYI: I don't have much experience in Go - so any hints about styling or optimizations are welcome!

@maltemorgenstern
Copy link
Copy Markdown
Contributor Author

Hey @chen-keinan, just wanted to check in - what to you think about these changes?
Thanks!

@github-actions
Copy link
Copy Markdown

This PR is stale because it has been labeled with inactivity.

@github-actions github-actions bot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and will be auto-closed. label Oct 13, 2024
@maltemorgenstern
Copy link
Copy Markdown
Contributor Author

Hey, we would still like this to be merged. @chen-keinan do you mind giving it a review?

@github-actions github-actions bot removed the lifecycle/stale Denotes an issue or PR has remained open with no activity and will be auto-closed. label Oct 14, 2024
@simar7 simar7 requested review from afdesk and removed request for chen-keinan December 3, 2024 06:09
@simar7
Copy link
Copy Markdown
Member

simar7 commented Jan 16, 2025

@afdesk could you take a look when you have a chance?

@afdesk afdesk added this to the v0.24.0 milestone Jan 30, 2025
@afdesk
Copy link
Copy Markdown
Contributor

afdesk commented Jan 30, 2025

@maltemorgenstern
thanks a lot for your contribution and sorry for really long delay to your PR.

can we follow up this job? thanks

@maltemorgenstern
Copy link
Copy Markdown
Contributor Author

Hey @afdesk and @simar7,
thanks for looking into this MR. I will try to rebase/update the branch in the next few days (just need to find some time) 👍

@afdesk
Copy link
Copy Markdown
Contributor

afdesk commented Feb 3, 2025

@maltemorgenstern great to hear it! thanks a lot for your contribution!

we (@simar7 ) have a concern about backward compatibilities, please, feel free to correct me.

Now globalAccessEnabled is disabled by default, right?
maybe should we keep it true by default?

@afdesk
Copy link
Copy Markdown
Contributor

afdesk commented Feb 3, 2025

@maltemorgenstern could you also rebase the PR with the main branch? thanks

Copy link
Copy Markdown
Contributor

@afdesk afdesk left a comment

Choose a reason for hiding this comment

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

I left some marks

Comment on lines +274 to +282
} else {
// Global access is disabled - check if privateRegistrySecrets references an imagePullSecret in the operator namespace
imagePullSecretName, ok := privateRegistrySecrets[r.Config.Namespace]
if ok {
// privateRegistrySecrets references an imagePullSecret in the operator namespace - use this for pulling private images
credentials, err = r.CredentialsByServer(ctx, owner, map[string]string{r.Config.Namespace: imagePullSecretName}, multiSecretSupport, false)
if err != nil {
return err
}
Copy link
Copy Markdown
Contributor

@afdesk afdesk Feb 3, 2025

Choose a reason for hiding this comment

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

this else statement will run If reusedReports isn't empty

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

changed 9d514f8

Comment on lines +256 to +266
privateRegistrySecrets, err := r.Config.GetPrivateRegistryScanSecretsNames()
if err != nil {
return err
}

pConfig, err := r.PluginContext.GetConfig()
if err != nil {
return err
}

multiSecretSupport := trivy.MultiSecretSupport(trivy.Config{PluginConfig: pConfig})
Copy link
Copy Markdown
Contributor

@afdesk afdesk Feb 3, 2025

Choose a reason for hiding this comment

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

also I have a concern about this block.
should we run it for existed KBOM reports?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

refactored 9e98218

@simar7 simar7 modified the milestones: v0.24.0, v0.25.0 Feb 4, 2025
@simar7 simar7 removed this from the v0.25.0 milestone Mar 5, 2025
@simar7 simar7 added this to the v0.26.0 milestone Mar 5, 2025
@simar7 simar7 removed this from the v0.26.0 milestone May 8, 2025
@afdesk afdesk force-pushed the 2158-private-images-without-global-access branch 2 times, most recently from 74e1f17 to 46ef0f6 Compare June 2, 2025 10:51
@afdesk afdesk requested a review from simar7 June 2, 2025 12:15
@afdesk
Copy link
Copy Markdown
Contributor

afdesk commented Jun 2, 2025

@simar7 @maltemorgenstern
I've updated a bit this useful PR.
could you take another look again?
thanks

@simar7 simar7 merged commit 727a447 into aquasecurity:main Jun 9, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Configure trivy-operator to use single ImagePullSecret from operator namespace without enabling global secret access

4 participants