Skip to content

Static Manifest Support#411

Merged
kfox1111 merged 26 commits intospiffe:mainfrom
kfox1111:static
Apr 16, 2025
Merged

Static Manifest Support#411
kfox1111 merged 26 commits intospiffe:mainfrom
kfox1111:static

Conversation

@kfox1111
Copy link
Copy Markdown
Collaborator

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

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>
@kfox1111 kfox1111 marked this pull request as draft September 15, 2024 00:49
Comment thread cmd/main.go Outdated
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>
@kfox1111 kfox1111 marked this pull request as ready for review December 15, 2024 03:33
return nil, err
}
for _, file := range files {
var entry = ClusterFederatedTrustDomain{}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
var entry = ClusterFederatedTrustDomain{}
var entry ClusterFederatedTrustDomain

but instead of creating variable here, what do you think about LoadClusterFederatedTrustDomainFromFile returning the Entry object instead?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is LoadClusterFederatedTrustDomainFromFile intended to be used out of this package?
if not can you remove and use loadClusterFederatedTrustDomainFile instead?

Comment on lines +57 to +59
if entry.APIVersion != "spire.spiffe.io/v1alpha1" || entry.Kind != "ClusterStaticEntry" {
continue
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Collaborator Author

@kfox1111 kfox1111 Apr 14, 2025

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Added some comments to help try and make things more clear.

Comment thread cmd/main.go
retval.reconcile.ClusterSPIFFEIDs = true
retval.reconcile.ClusterFederatedTrustDomains = true
retval.reconcile.ClusterStaticEntries = true
if retval.ctrlConfig.StaticManifestPath == nil {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can you add a quick comment about only one is supported?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

That only one static manifest path can be watched?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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.

Comment thread cmd/main.go Outdated
Comment on lines +340 to +344
if mainConfig.ctrlConfig.StaticManifestPath != nil {
mgr, err = ctrl.NewManager(&rest.Config{}, mainConfig.options)
} else {
mgr, err = ctrl.NewManager(ctrl.GetConfigOrDie(), mainConfig.options)
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

how about:

restConfig := &rest.Config{}
if mainConfig.ctrlConfig.StaticManifestPath == nil {
  restConfig = ctrl.GetConfigOrDie()
}
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), mainConfig.options)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Looks good. except splitting the two run functions made this no longer needed.

Comment thread cmd/main.go Outdated

func run(mainConfig Config) (err error) {
webhookEnabled := os.Getenv("ENABLE_WEBHOOKS") != "false"
if mainConfig.ctrlConfig.StaticManifestPath != nil {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

may we add documentation or a way so users can know than webhook is not going to work if staticmanifestpath is set?

Comment thread cmd/main.go Outdated
Comment on lines +373 to +375
if mainConfig.ctrlConfig.StaticManifestPath == nil {
k8sClient = mgr.GetClient()
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

client is already set in 352, is this new get required? (same comment to all lines like this)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Not sure. was just reproducing the existing behavior before the change. But the duplicated run now undoes this change.

Comment thread cmd/main.go Outdated
if mainConfig.ctrlConfig.StaticManifestPath != nil {
mgr, err = ctrl.NewManager(&rest.Config{}, mainConfig.options)
} else {
mgr, err = ctrl.NewManager(ctrl.GetConfigOrDie(), mainConfig.options)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

oh. left over from before. will fix.

Comment thread cmd/main.go Outdated
}
}
go func() {
err = entryReconciler.Run(context.TODO())
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

should we run this only when entryReconciler is initialized? maybe using a pointer here?
Same for federation

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can you use the same context for everything? the one from ctx := ctrl.SetupSignalHandler() so if that on is canceled all finish as expected

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

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

Comment thread cmd/main.go
}

setupLog.Info("starting manager")
if err := mgr.Start(ctx); err != nil {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah. Thats a good thought. Will add

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done

Comment thread pkg/spireentry/reconciler.go Outdated
clusterStaticEntries, err = k8sapi.ListClusterStaticEntries(ctx, r.config.K8sClient)
} else {
// FIXME prebuild / pass scheme?
scheme := runtime.NewScheme()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

are you planing to improve this schema? if it is not used until the very end may we create it there?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

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" {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

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?

Comment thread docs/spire-controller-manager-config.md Outdated
kfox1111 and others added 2 commits April 16, 2025 07:17
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>
@kfox1111 kfox1111 merged commit e994f56 into spiffe:main Apr 16, 2025
6 checks passed
@MarcosDY MarcosDY added this to the 0.6.2 milestone Apr 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants