Conversation
Enables watching a directory for CRs to configure SPIRE with rather then get them from Kubernetes. This allows for simple to configure stand alone SPIRE servers, easy integration with traditional configuration management systems, and/or easy syncing of config from git. It supports: * ClusterStaticEntries * ClusterFederatedTrustDomains Signed-off-by: Kevin Fox <Kevin.Fox@pnnl.gov>
Signed-off-by: kfox1111 <Kevin.Fox@pnnl.gov>
Signed-off-by: Kevin Fox <Kevin.Fox@pnnl.gov>
Signed-off-by: Kevin Fox <Kevin.Fox@pnnl.gov>
Signed-off-by: Kevin Fox <Kevin.Fox@pnnl.gov>
Signed-off-by: Kevin Fox <Kevin.Fox@pnnl.gov>
Signed-off-by: Kevin Fox <Kevin.Fox@pnnl.gov>
Signed-off-by: kfox1111 <Kevin.Fox@pnnl.gov>
Signed-off-by: Kevin Fox <Kevin.Fox@pnnl.gov>
| return nil, err | ||
| } | ||
| for _, file := range files { | ||
| var entry = ClusterFederatedTrustDomain{} |
There was a problem hiding this comment.
| var entry = ClusterFederatedTrustDomain{} | |
| var entry ClusterFederatedTrustDomain |
but instead of creating variable here, what do you think about LoadClusterFederatedTrustDomainFromFile returning the Entry object instead?
There was a problem hiding this comment.
is LoadClusterFederatedTrustDomainFromFile intended to be used out of this package?
if not can you remove and use loadClusterFederatedTrustDomainFile instead?
| if entry.APIVersion != "spire.spiffe.io/v1alpha1" || entry.Kind != "ClusterStaticEntry" { | ||
| continue | ||
| } |
There was a problem hiding this comment.
if parse fails entry is going to be empty, and always continue here, so error is dismissed, can you check error first?
or are you trying to always process all files? if that is the came, maybe we can add logs?
There was a problem hiding this comment.
Yeah. Was thinking dropping in one bad file shouldn't break syncing the good ones. +1 for logging.
Actually, re reviewing the code, it does throw an error in the next conditional. The idea being, if you typo an entry you previously had, it doesn't retract the entry during sync, breaking something working. Better to break syncing, which you can catch, then retract something.
The APIVersion/Kind thing though happens before error checking, as it could have tried to parse other types in the same dir, and the check ignores failures in files its not intending to parse.
There was a problem hiding this comment.
Added some comments to help try and make things more clear.
| retval.reconcile.ClusterSPIFFEIDs = true | ||
| retval.reconcile.ClusterFederatedTrustDomains = true | ||
| retval.reconcile.ClusterStaticEntries = true | ||
| if retval.ctrlConfig.StaticManifestPath == nil { |
There was a problem hiding this comment.
can you add a quick comment about only one is supported?
There was a problem hiding this comment.
That only one static manifest path can be watched?
There was a problem hiding this comment.
Oh... This is setting the defaults.
If the user didn't set which things are reconciled explicitly, this sets the defaults depending on if in static mode.
if static, default reconcile option is:
clusterSPIFFEIDs: false
clusterFederatedTrustDomains: true
clusterStaticEntries: true
if k8s mode, default reconcile option is:
clusterSPIFFEIDs: true
clusterFederatedTrustDomains: true
clusterStaticEntries: true
I guess the conditional could be removed and just set:
retval.reconcile.ClusterSPIFFEIDs = retval.ctrlConfig.StaticManifestPath == nil
Not sure that is more clear or not though...What do you think?
There was a problem hiding this comment.
This comment refers to the old implementation and is no longer relevant after the recent refactor. However, adding a brief explanation for why ClusterSPIFFEIDs is set to true when clusterStaticEntry is set would still be valuable for future readers.
Regarding the if vs ==, using if feels clear to me since the intent is easy to understand at a glance.
| if mainConfig.ctrlConfig.StaticManifestPath != nil { | ||
| mgr, err = ctrl.NewManager(&rest.Config{}, mainConfig.options) | ||
| } else { | ||
| mgr, err = ctrl.NewManager(ctrl.GetConfigOrDie(), mainConfig.options) | ||
| } |
There was a problem hiding this comment.
how about:
restConfig := &rest.Config{}
if mainConfig.ctrlConfig.StaticManifestPath == nil {
restConfig = ctrl.GetConfigOrDie()
}
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), mainConfig.options)
There was a problem hiding this comment.
Looks good. except splitting the two run functions made this no longer needed.
|
|
||
| func run(mainConfig Config) (err error) { | ||
| webhookEnabled := os.Getenv("ENABLE_WEBHOOKS") != "false" | ||
| if mainConfig.ctrlConfig.StaticManifestPath != nil { |
There was a problem hiding this comment.
may we add documentation or a way so users can know than webhook is not going to work if staticmanifestpath is set?
| if mainConfig.ctrlConfig.StaticManifestPath == nil { | ||
| k8sClient = mgr.GetClient() | ||
| } |
There was a problem hiding this comment.
client is already set in 352, is this new get required? (same comment to all lines like this)
There was a problem hiding this comment.
Not sure. was just reproducing the existing behavior before the change. But the duplicated run now undoes this change.
| if mainConfig.ctrlConfig.StaticManifestPath != nil { | ||
| mgr, err = ctrl.NewManager(&rest.Config{}, mainConfig.options) | ||
| } else { | ||
| mgr, err = ctrl.NewManager(ctrl.GetConfigOrDie(), mainConfig.options) |
There was a problem hiding this comment.
this is never going to be true right?
we are only going to call static when StaticManifestPath != nil,
if that is the case may we fail here?
There was a problem hiding this comment.
oh. left over from before. will fix.
| } | ||
| } | ||
| go func() { | ||
| err = entryReconciler.Run(context.TODO()) |
There was a problem hiding this comment.
should we run this only when entryReconciler is initialized? maybe using a pointer here?
Same for federation
There was a problem hiding this comment.
can you use the same context for everything? the one from ctx := ctrl.SetupSignalHandler() so if that on is canceled all finish as expected
There was a problem hiding this comment.
should we run this only when entryReconciler is initialized? maybe using a pointer here?
Same for federation
Hmm.... without the interleaved k8s code in the staticRun function, I think we can just move it up into the conditionals above to guard that. Done
| } | ||
|
|
||
| setupLog.Info("starting manager") | ||
| if err := mgr.Start(ctx); err != nil { |
There was a problem hiding this comment.
is it possible to get into an edge case caused by go routines didnt start at before this one?
if that is the case may we use groups?
There was a problem hiding this comment.
Yeah. Thats a good thought. Will add
| clusterStaticEntries, err = k8sapi.ListClusterStaticEntries(ctx, r.config.K8sClient) | ||
| } else { | ||
| // FIXME prebuild / pass scheme? | ||
| scheme := runtime.NewScheme() |
There was a problem hiding this comment.
are you planing to improve this schema? if it is not used until the very end may we create it there?
There was a problem hiding this comment.
Not intending on it. Moved.
Signed-off-by: Kevin Fox <Kevin.Fox@pnnl.gov>
| err = LoadClusterFederatedTrustDomainFromFile(fullfile, scheme, &entry, expandEnv) | ||
| entry, err := loadClusterFederatedTrustDomainFile(fullfile, scheme, expandEnv) | ||
| // Ignore files of the wrong type in manifestPath | ||
| if entry.APIVersion != "spire.spiffe.io/v1alpha1" || entry.Kind != "ClusterFederatedTrustDomain" { |
There was a problem hiding this comment.
is not this going to cause than all errors are avoid? because we are going to return an empty entry and continue is going to always call,
may we log errors so users can understand why their files are not loaded? (same comment to statis entry)
There was a problem hiding this comment.
The same directory contains multiple types of files, parsed by different loops. so a file ignored here are picked up in say, api/v1alpha1/clusterstaticentry_loader.go. The only way to log the ignored ones would be to keep track of the files processed by each of the two reconciliation loops, synchronizing the passes, and then log the difference. Very tricky. :(
The juice is probably not worth the squeeze. Maybe we don't and if users request it, we reevaluate?
Signed-off-by: Kevin Fox <Kevin.Fox@pnnl.gov>
Co-authored-by: Marcos Yacob <marcosyacob@gmail.com> Signed-off-by: kfox1111 <Kevin.Fox@pnnl.gov>
Enables watching a directory for CRs to configure SPIRE with rather then get them from Kubernetes. This allows for simple to configure stand alone SPIRE servers, easy integration with traditional configuration management systems, and/or easy syncing of config from git.
It supports: