Merge pull request #305 from SomtochiAma/no-cross-ns-ref
Allow disabling cross-namespace references
This commit is contained in:
commit
6aaf01a6ee
|
@ -29,7 +29,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Masterminds/sprig/v3"
|
||||
|
||||
gogit "github.com/go-git/go-git/v5"
|
||||
libgit2 "github.com/libgit2/git2go/v31"
|
||||
|
||||
|
@ -55,7 +54,9 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
|
||||
imagev1_reflect "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
apiacl "github.com/fluxcd/pkg/apis/acl"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/runtime/acl"
|
||||
"github.com/fluxcd/pkg/runtime/events"
|
||||
"github.com/fluxcd/pkg/runtime/logger"
|
||||
"github.com/fluxcd/pkg/runtime/metrics"
|
||||
|
@ -91,6 +92,7 @@ type ImageUpdateAutomationReconciler struct {
|
|||
EventRecorder kuberecorder.EventRecorder
|
||||
ExternalEventRecorder *events.Recorder
|
||||
MetricsRecorder *metrics.Recorder
|
||||
NoCrossNamespaceRef bool
|
||||
}
|
||||
|
||||
type ImageUpdateAutomationReconcilerOptions struct {
|
||||
|
@ -179,6 +181,19 @@ func (r *ImageUpdateAutomationReconciler) Reconcile(ctx context.Context, req ctr
|
|||
}
|
||||
debuglog.Info("fetching git repository", "gitrepository", originName)
|
||||
|
||||
if r.NoCrossNamespaceRef && gitRepoNamespace != auto.GetNamespace() {
|
||||
err := acl.AccessDeniedError(fmt.Sprintf("can't access '%s/%s', cross-namespace references have been blocked",
|
||||
auto.Spec.SourceRef.Kind, originName))
|
||||
log.Error(err, "access denied to cross-namespaced resource")
|
||||
imagev1.SetImageUpdateAutomationReadiness(&auto, metav1.ConditionFalse, apiacl.AccessDeniedReason,
|
||||
err.Error())
|
||||
if err := r.patchStatus(ctx, req, auto.Status); err != nil {
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
r.event(ctx, auto, events.EventSeverityError, err.Error())
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
if err := r.Get(ctx, originName, &origin); err != nil {
|
||||
if client.IgnoreNotFound(err) == nil {
|
||||
imagev1.SetImageUpdateAutomationReadiness(&auto, metav1.ConditionFalse, imagev1.GitNotAvailableReason, "referenced git repository is missing")
|
||||
|
|
|
@ -30,6 +30,7 @@ import (
|
|||
|
||||
"github.com/ProtonMail/go-crypto/openpgp"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/armor"
|
||||
"github.com/fluxcd/pkg/apis/acl"
|
||||
"github.com/go-git/go-billy/v5/memfs"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
|
@ -268,6 +269,7 @@ Images:
|
|||
})
|
||||
|
||||
AfterEach(func() {
|
||||
imageAutoReconciler.NoCrossNamespaceRef = false
|
||||
Expect(k8sClient.Delete(context.Background(), namespace)).To(Succeed())
|
||||
})
|
||||
|
||||
|
@ -290,8 +292,9 @@ Images:
|
|||
|
||||
Context("ref cross-ns GitRepository", func() {
|
||||
var (
|
||||
localRepo *git.Repository
|
||||
commitMessage string
|
||||
localRepo *git.Repository
|
||||
commitMessage string
|
||||
updateBySetters *imagev1.ImageUpdateAutomation
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -410,7 +413,7 @@ Images:
|
|||
Namespace: namespace.Name,
|
||||
Name: "update-test",
|
||||
}
|
||||
updateBySetters := &imagev1.ImageUpdateAutomation{
|
||||
updateBySetters = &imagev1.ImageUpdateAutomation{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: updateKey.Name,
|
||||
Namespace: updateKey.Namespace,
|
||||
|
@ -465,6 +468,28 @@ Images:
|
|||
Expect(commit.Author.Name).To(Equal(authorName))
|
||||
Expect(commit.Author.Email).To(Equal(authorEmail))
|
||||
})
|
||||
|
||||
It("fails to reconcile if cross-namespace flag is set", func() {
|
||||
imageAutoReconciler.NoCrossNamespaceRef = true
|
||||
|
||||
// trigger reconcile
|
||||
var updatePatch imagev1.ImageUpdateAutomation
|
||||
Expect(k8sClient.Get(context.TODO(), client.ObjectKeyFromObject(updateBySetters), &updatePatch)).To(Succeed())
|
||||
updatePatch.Spec.Interval = metav1.Duration{Duration: 5 * time.Minute}
|
||||
Expect(k8sClient.Patch(context.Background(), &updatePatch, client.Merge)).To(Succeed())
|
||||
|
||||
resultAuto := &imagev1.ImageUpdateAutomation{}
|
||||
var readyCondition *metav1.Condition
|
||||
|
||||
Eventually(func() bool {
|
||||
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(updateBySetters), resultAuto)
|
||||
readyCondition = apimeta.FindStatusCondition(resultAuto.Status.Conditions, meta.ReadyCondition)
|
||||
return apimeta.IsStatusConditionFalse(resultAuto.Status.Conditions, meta.ReadyCondition)
|
||||
}, timeout, time.Second).Should(BeTrue())
|
||||
|
||||
Expect(readyCondition).ToNot(BeNil())
|
||||
Expect(readyCondition.Reason).To(Equal(acl.AccessDeniedReason))
|
||||
})
|
||||
})
|
||||
|
||||
Context("update path", func() {
|
||||
|
|
|
@ -32,7 +32,7 @@ type ImageUpdateAutomationSpec struct {
|
|||
// SourceRef refers to the resource giving access details
|
||||
// to a git repository.
|
||||
// +required
|
||||
SourceRef SourceReference `json:"sourceRef"`
|
||||
SourceRef CrossNamespaceSourceReference `json:"sourceRef"`
|
||||
// GitSpec contains all the git-specific definitions. This is
|
||||
// technically optional, but in practice mandatory until there are
|
||||
// other kinds of source allowed.
|
||||
|
@ -62,25 +62,51 @@ repository to be updated. The `kind` field in the reference currently only suppo
|
|||
`GitRepository`, which is the default.
|
||||
|
||||
```go
|
||||
// SourceReference contains enough information to let you locate the
|
||||
// typed, referenced source object.
|
||||
type SourceReference struct {
|
||||
// API version of the referent
|
||||
// CrossNamespaceSourceReference contains enough information to let you locate the
|
||||
// typed Kubernetes resource object at cluster level.
|
||||
type CrossNamespaceSourceReference struct {
|
||||
// API version of the referent.
|
||||
// +optional
|
||||
APIVersion string `json:"apiVersion,omitempty"`
|
||||
|
||||
// Kind of the referent
|
||||
// Kind of the referent.
|
||||
// +kubebuilder:validation:Enum=GitRepository
|
||||
// +kubebuilder:default=GitRepository
|
||||
// +required
|
||||
Kind string `json:"kind"`
|
||||
|
||||
// Name of the referent
|
||||
// Name of the referent.
|
||||
// +required
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace of the referent, defaults to the namespace of the Kubernetes resource object that contains the reference.
|
||||
// +optional
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
### Cross-namespace references
|
||||
|
||||
A ImageUpdateAutomation can refer to a GitRepository from a different namespace with
|
||||
`spec.sourceRef.namespace` e.g.:
|
||||
|
||||
```yaml
|
||||
apiVersion: image.toolkit.fluxcd.io/v1beta1
|
||||
kind: ImageUpdateAutomation
|
||||
metadata:
|
||||
name: webapp
|
||||
namespace: apps
|
||||
spec:
|
||||
interval: 5m
|
||||
sourceRef:
|
||||
kind: GitRepository # the only valid value, but good practice to be explicit here
|
||||
name: apps
|
||||
namespace: flux-system
|
||||
```
|
||||
|
||||
On multi-tenant clusters, platform admins can disable cross-namespace references with the
|
||||
`--no-cross-namespace-refs=true` flag.
|
||||
|
||||
To be able to commit changes back, the referenced `GitRepository` object must refer to credentials
|
||||
with write access; e.g., if using a GitHub deploy key, "Allow write access" should be checked when
|
||||
creating it. Only the `url`, `ref`, and `secretRef` fields of the `GitRepository` are used.
|
||||
|
|
2
go.mod
2
go.mod
|
@ -13,7 +13,7 @@ require (
|
|||
github.com/fluxcd/image-reflector-controller/api v0.15.0
|
||||
github.com/fluxcd/pkg/apis/meta v0.10.2
|
||||
github.com/fluxcd/pkg/gittestserver v0.5.0
|
||||
github.com/fluxcd/pkg/runtime v0.12.3
|
||||
github.com/fluxcd/pkg/runtime v0.12.4
|
||||
github.com/fluxcd/pkg/ssh v0.2.0
|
||||
// If you bump this, change SOURCE_VER in the Makefile to match
|
||||
github.com/fluxcd/source-controller v0.21.0
|
||||
|
|
3
go.sum
3
go.sum
|
@ -366,8 +366,9 @@ github.com/fluxcd/pkg/gitutil v0.1.0 h1:VO3kJY/CKOCO4ysDNqfdpTg04icAKBOSb3lbR5uE
|
|||
github.com/fluxcd/pkg/gitutil v0.1.0/go.mod h1:Ybz50Ck5gkcnvF0TagaMwtlRy3X3wXuiri1HVsK5id4=
|
||||
github.com/fluxcd/pkg/helmtestserver v0.4.0/go.mod h1:JOI9f3oXUFIWmMKWMBan7FjglAU+fRTO/sPPV/Kj3gQ=
|
||||
github.com/fluxcd/pkg/lockedfile v0.1.0/go.mod h1:EJLan8t9MiOcgTs8+puDjbE6I/KAfHbdvIy9VUgIjm8=
|
||||
github.com/fluxcd/pkg/runtime v0.12.3 h1:h21AZ3YG5MAP7DxFF9hfKrP+vFzys2L7CkUbPFjbP/0=
|
||||
github.com/fluxcd/pkg/runtime v0.12.3/go.mod h1:imJ2xYy/d4PbSinX2IefmZk+iS2c1P5fY0js8mCE4SM=
|
||||
github.com/fluxcd/pkg/runtime v0.12.4 h1:gA27RG/+adN2/7Qe03PB46Iwmye/MusPCpuS4zQ2fW0=
|
||||
github.com/fluxcd/pkg/runtime v0.12.4/go.mod h1:gspNvhAqodZgSmK1ZhMtvARBf/NGAlxmaZaIOHkJYsc=
|
||||
github.com/fluxcd/pkg/ssh v0.2.0 h1:e9V+HReOL7czm7edVzYS1e+CnFKz1/kHiUNfLRpBdH8=
|
||||
github.com/fluxcd/pkg/ssh v0.2.0/go.mod h1:EpQC7Ztdlbi8S/dlYXqVDZtHtLpN3FNl3N6zWujVzbA=
|
||||
github.com/fluxcd/pkg/testserver v0.1.0/go.mod h1:fvt8BHhXw6c1+CLw1QFZxcQprlcXzsrL4rzXaiGM+Iw=
|
||||
|
|
4
main.go
4
main.go
|
@ -29,6 +29,7 @@ import (
|
|||
ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||
|
||||
imagev1_reflect "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
"github.com/fluxcd/pkg/runtime/acl"
|
||||
"github.com/fluxcd/pkg/runtime/client"
|
||||
"github.com/fluxcd/pkg/runtime/events"
|
||||
"github.com/fluxcd/pkg/runtime/leaderelection"
|
||||
|
@ -64,6 +65,7 @@ func main() {
|
|||
eventsAddr string
|
||||
healthAddr string
|
||||
clientOptions client.Options
|
||||
aclOptions acl.Options
|
||||
logOptions logger.Options
|
||||
leaderElectionOptions leaderelection.Options
|
||||
watchAllNamespaces bool
|
||||
|
@ -79,6 +81,7 @@ func main() {
|
|||
clientOptions.BindFlags(flag.CommandLine)
|
||||
logOptions.BindFlags(flag.CommandLine)
|
||||
leaderElectionOptions.BindFlags(flag.CommandLine)
|
||||
aclOptions.BindFlags(flag.CommandLine)
|
||||
flag.Parse()
|
||||
|
||||
log := logger.NewLogger(logOptions)
|
||||
|
@ -130,6 +133,7 @@ func main() {
|
|||
EventRecorder: mgr.GetEventRecorderFor(controllerName),
|
||||
ExternalEventRecorder: eventRecorder,
|
||||
MetricsRecorder: metricsRecorder,
|
||||
NoCrossNamespaceRef: aclOptions.NoCrossNamespaceRefs,
|
||||
}).SetupWithManager(mgr, controllers.ImageUpdateAutomationReconcilerOptions{
|
||||
MaxConcurrentReconciles: concurrent,
|
||||
}); err != nil {
|
||||
|
|
Loading…
Reference in New Issue