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
OCPBUGS-5744: dockercfg: use tokenrequest instead of SA secrets #223
Conversation
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: stlaz The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
This also needs to implement token refresh. Possible issue: we need to rotate the token inside the secret, is the change in the secret propagated in the pod? |
generally, yes: https://kubernetes.io/docs/concepts/configuration/secret/#mounted-secrets-are-updated-automatically. But the pod is responsible for re-reading the value, either using a time based approach or by fsnotify. |
4889e36
to
f0c1de4
Compare
/retest |
/retest |
f0c1de4
to
2c53e05
Compare
00ecff4
to
7f552c7
Compare
7f552c7
to
7f9aaf0
Compare
/retest |
61bf205
to
4309267
Compare
a1f5947
to
bcb0404
Compare
} | ||
|
||
// NewDockercfgTokenDeletedController returns a new *DockercfgTokenDeletedController. | ||
func NewDockercfgTokenDeletedController(secrets informers.SecretInformer, cl kclientset.Interface, options DockercfgTokenDeletedControllerOptions) *DockercfgTokenDeletedController { |
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.
Without this controller, what deletes the token secrets when the dockercfg secret is deleted later on?
Is there an ownerref these days perhaps?
@@ -138,7 +138,7 @@ type DockerRegistryServiceController struct { | |||
} | |||
|
|||
// Runs controller loops and returns immediately | |||
func (e *DockerRegistryServiceController) Run(workers int, stopCh <-chan struct{}) { | |||
func (e *DockerRegistryServiceController) Run(ctx context.Context, workers int) { |
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.
pull stuff like this which are maintenance refactors without intent changes into a separate PR for easier review and merge
ServiceAccountTokenSecretNameKey = "openshift.io/token-secret.name" | ||
MaxRetriesBeforeResync = 5 | ||
MaxRetriesBeforeResync = 5 | ||
ExpirationCheckPeriod = 10 * time.Minute |
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.
if you make me look at a constant, I'll ask for godoc ;)
// token data population | ||
PendingTokenAnnotation = "openshift.io/create-dockercfg-secrets.pending-token" | ||
PendingTokenAnnotation = "openshift.io/create-dockercfg-secrets.pending-secret" |
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.
a change here looks suspicious. I would expect a new constant instead.
if !exists { | ||
continue | ||
serviceAccount.Annotations[PendingTokenAnnotation] = pendingTokenName | ||
updatedServiceAccount, err := e.client.CoreV1().ServiceAccounts(serviceAccount.Namespace).Update(ctx, serviceAccount, metav1.UpdateOptions{}) |
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 recommend using the apply client for this. You can do it as a separate step, but it will reduce conflicts.
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 was considering patch when looking through the code, this helped with with other controllers in the past.
klog.V(4).Infof("Creating dockercfg secret %q for service account %s/%s", dockercfgSecret.Name, serviceAccount.Namespace, serviceAccount.Name) | ||
|
||
// Save the secret | ||
_, err = e.client.CoreV1().Secrets(serviceAccount.Namespace).Create(ctx, dockercfgSecret, metav1.CreateOptions{}) |
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.
why create before getting the content? With the tokenrequest API, the call to get the content is synchronous and it would simplify some of the waiting logic, right?
EDIT: OH! it's because you need the secret for the bound token to bind to, isn't it? Still that's fast, (api calls, not controller response time), so you could do a secret create, a tokenrequest, a secret apply (avoid the conflict), and an SA update.
} | ||
|
||
func (c *DockercfgController) waitForDockerURLs(ready chan<- struct{}, stopCh <-chan struct{}) { | ||
func (c *DockercfgController) waitForDockerURLs(ctx context.Context, ready chan<- struct{}) { |
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.
separate from this PR (before or after), I wonder if these are still logically configurable. They used to be cyclical with the rest of the controller-manager so I built this logic, but I wonder if on openshift these are now practically fixed in a way that the names can be predicted during installation and reacted to if they ever change to avoid the interlock and self-discovery logic.
Just imagining future you trying to maintain this area of code.
pendingTokenName := serviceAccount.Annotations[PendingTokenAnnotation] | ||
|
||
// If this service account has no record of a pending token name, record one | ||
if len(pendingTokenName) == 0 { |
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.
If you can build a valid dockerconfig secret synchronously, you'd be able to first build the secret and second directly update the serviceaccount with the pull secret and never need the intermediate annotation, right?
Just so I'm clear, this is about how we handle new dockercfg secrets, but how do we migrate existing ones and how do existing ones delete the old token secret and use a new tokenrequest based token instead? |
default: | ||
utilruntime.HandleError(fmt.Errorf("object passed to %T that is not expected: %T", e, obj)) | ||
return false | ||
} | ||
}, | ||
Handler: cache.ResourceEventHandlerFuncs{ | ||
// We don't need to react to secret deletes, the deleted_dockercfg_secrets controller does that | ||
// It also updates the SA so we will eventually get back to creating a new secret |
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.
Since you already use FilteringResoruceEventHandler
it's sufficient for you to always e.enqueuSecret(secret)
} | ||
|
||
func (e *DockercfgController) enqueueServiceAccountForToken(tokenSecret *v1.Secret) { | ||
func (e *DockercfgController) enqueueServiceAccountForToken(dockerCfgSecret *v1.Secret) { |
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.
This looks like it's not being used anywhere.
dockercfg[dockerURL] = credentialprovider.DockerConfigEntry{ | ||
Username: "serviceaccount", | ||
Password: string(saToken), | ||
Email: "serviceaccount@example.org", |
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.
The email shouldn't be needed, looking at my own .docker/config.json
so I'd suggest dropping it.
if !exists { | ||
continue | ||
serviceAccount.Annotations[PendingTokenAnnotation] = pendingTokenName | ||
updatedServiceAccount, err := e.client.CoreV1().ServiceAccounts(serviceAccount.Namespace).Update(ctx, serviceAccount, metav1.UpdateOptions{}) |
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 was considering patch when looking through the code, this helped with with other controllers in the past.
@stlaz: PR needs rebase. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
@stlaz: The following tests failed, say
Full PR test history. Your PR dashboard. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
Issues go stale after 90d of inactivity. Mark the issue as fresh by commenting If this issue is safe to close now please do so with /lifecycle stale |
/remove-lifecycle stale |
Issues go stale after 90d of inactivity. Mark the issue as fresh by commenting If this issue is safe to close now please do so with /lifecycle stale |
Stale issues rot after 30d of inactivity. Mark the issue as fresh by commenting If this issue is safe to close now please do so with /lifecycle rotten |
Rotten issues close after 30d of inactivity. Reopen the issue by commenting /close |
@openshift-bot: Closed this PR. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
@stlaz: An error was encountered updating to the NEW state for bug OCPBUGS-5744 on the Jira server at https://issues.redhat.com/. No known errors were detected, please see the full error message for details. Full error message.
No transition status with name `NEW` could be found. Please select from the following list: [Replan]
Please contact an administrator to resolve this issue, then request a bug refresh with In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
this PR makes use of the TokenRequest API to get a token for the dockercfg SA secret rather than creating a secret and polluting etcd for that very same purpose,