Skip to content

Commit

Permalink
Add flag to disable cross namespace references
Browse files Browse the repository at this point in the history
Signed-off-by: Somtochi Onyekwere <[email protected]>
  • Loading branch information
somtochiama committed Jan 28, 2022
1 parent 413717a commit bf0a366
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 4 deletions.
11 changes: 10 additions & 1 deletion controllers/helmrelease_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"

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/metrics"
"github.com/fluxcd/pkg/runtime/predicates"
Expand Down Expand Up @@ -78,6 +80,7 @@ type HelmReleaseReconciler struct {
EventRecorder kuberecorder.EventRecorder
ExternalEventRecorder *events.Recorder
MetricsRecorder *metrics.Recorder
NoCrossNamespaceRef bool
}

func (r *HelmReleaseReconciler) SetupWithManager(mgr ctrl.Manager, opts HelmReleaseReconcilerOptions) error {
Expand Down Expand Up @@ -213,9 +216,15 @@ func (r *HelmReleaseReconciler) reconcile(ctx context.Context, hr v2.HelmRelease
// Reconcile chart based on the HelmChartTemplate
hc, reconcileErr := r.reconcileChart(ctx, &hr)
if reconcileErr != nil {
reason := v2.ArtifactFailedReason
if acl.IsAccessDenied(reconcileErr) {
reason = apiacl.AccessDeniedReason
log.Error(reconcileErr, "access denied to cross-namespace source")
}

msg := fmt.Sprintf("chart reconciliation failed: %s", reconcileErr.Error())
r.event(ctx, hr, hr.Status.LastAttemptedRevision, events.EventSeverityError, msg)
return v2.HelmReleaseNotReady(hr, v2.ArtifactFailedReason, msg), ctrl.Result{Requeue: true}, reconcileErr
return v2.HelmReleaseNotReady(hr, reason, msg), ctrl.Result{Requeue: true}, reconcileErr
}

// Check chart readiness
Expand Down
6 changes: 6 additions & 0 deletions controllers/helmrelease_controller_chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"reflect"
"strings"

"github.com/fluxcd/pkg/runtime/acl"
"github.com/hashicorp/go-retryablehttp"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
Expand All @@ -46,6 +47,11 @@ func (r *HelmReleaseReconciler) reconcileChart(ctx context.Context, hr *v2.HelmR
Namespace: hr.Spec.Chart.GetNamespace(hr.Namespace),
Name: hr.GetHelmChartName(),
}

if r.NoCrossNamespaceRef && chartName.Namespace != hr.Namespace {
return nil, acl.AccessDeniedError(fmt.Sprintf("can't access 'HelmChart/%s', cross-namespace references have beem blocked",
chartName))
}

// Garbage collect the previous HelmChart if the namespace named changed.
if hr.Status.HelmChart != "" && hr.Status.HelmChart != chartName.String() {
Expand Down
31 changes: 30 additions & 1 deletion controllers/helmrelease_controller_chart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func TestHelmReleaseReconciler_reconcileChart(t *testing.T) {
expectHelmChartStatus string
expectGC bool
expectErr bool
noCrossNamspaceRef bool
}{
{
name: "new HelmChart",
Expand Down Expand Up @@ -140,6 +141,33 @@ func TestHelmReleaseReconciler_reconcileChart(t *testing.T) {
expectHelmChartStatus: "cross/default-test-release",
expectGC: true,
},
{
name: "block cross namespace access when flag is set",
hr: &v2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: "test-release",
Namespace: "default",
},
Spec: v2.HelmReleaseSpec{
Interval: metav1.Duration{Duration: time.Minute},
Chart: v2.HelmChartTemplate{
Spec: v2.HelmChartTemplateSpec{
Chart: "chart",
SourceRef: v2.CrossNamespaceObjectReference{
Name: "test-repository",
Kind: "HelmRepository",
Namespace: "cross",
},
},
},
},
Status: v2.HelmReleaseStatus{
HelmChart: "",
},
},
noCrossNamspaceRef: true,
expectErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -156,7 +184,8 @@ func TestHelmReleaseReconciler_reconcileChart(t *testing.T) {
}

r := &HelmReleaseReconciler{
Client: c,
Client: c,
NoCrossNamespaceRef: tt.noCrossNamspaceRef,
}

hc, err := r.reconcileChart(logr.NewContext(context.TODO(), logr.Discard()), tt.hr)
Expand Down
9 changes: 9 additions & 0 deletions docs/spec/v2beta1/helmreleases.md
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,15 @@ The `spec.chart.spec.sourceRef` is a reference to an object managed by
[revision](https://github.com/fluxcd/source-controller/blob/main/docs/spec/v1beta1/common.md#source-status)
changes, it generates a Kubernetes event that triggers a new release.

> **Note** that on multi-tenant clusters, platform admins can disable cross-namespace references
> with the `--no-cross-namespace-refs=true` flag. When this flag is set, the helmrelease can only
> refer to sources in the same namespace as the helmrelease object.
> **Note** that on multi-tenant clusters, platform admins can disable cross-namespace references
> with the `--no-cross-namespace-refs=true` flag. When this flag is set, alerts can only refer to
> event sources in the same namespace as the alert object,
> preventing tenants from subscribing to another tenant's events.
Supported source types:

- [HelmRepository](https://github.com/fluxcd/source-controller/blob/main/docs/spec/v1beta1/helmrepositories.md)
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/fluxcd/helm-controller/api v0.15.0
github.com/fluxcd/pkg/apis/kustomize v0.3.1
github.com/fluxcd/pkg/apis/meta v0.10.2
github.com/fluxcd/pkg/runtime v0.12.3
github.com/fluxcd/pkg/runtime v0.12.4
github.com/fluxcd/source-controller/api v0.20.1
github.com/garyburd/redigo v1.6.3 // indirect
github.com/go-logr/logr v1.2.2
Expand All @@ -31,6 +31,8 @@ require (
sigs.k8s.io/yaml v1.3.0
)

require github.com/fluxcd/pkg/apis/acl v0.0.3

require (
cloud.google.com/go v0.81.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
Expand Down Expand Up @@ -61,7 +63,6 @@ require (
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
github.com/fatih/color v1.7.0 // indirect
github.com/fluxcd/pkg/apis/acl v0.0.3 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-logr/zapr v1.2.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ github.com/fluxcd/pkg/apis/meta v0.10.2 h1:pnDBBEvfs4HaKiVAYgz+e/AQ8dLvcgmVfSeBr
github.com/fluxcd/pkg/apis/meta v0.10.2/go.mod h1:KQ2er9xa6koy7uoPMZjIjNudB5p4tXs+w0GO6fRcy7I=
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/source-controller/api v0.20.1 h1:BfYw1gNHykiCVFNtDz3atcf3Vph+arfuveKmouI98wE=
github.com/fluxcd/source-controller/api v0.20.1/go.mod h1:Ab2qDmAUz6ZCp8UaHYLYzxyFrC1FQqEqjxiROb/Rdiw=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
Expand Down
4 changes: 4 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
crtlmetrics "sigs.k8s.io/controller-runtime/pkg/metrics"

"github.com/fluxcd/pkg/runtime/acl"
"github.com/fluxcd/pkg/runtime/client"
"github.com/fluxcd/pkg/runtime/events"
"github.com/fluxcd/pkg/runtime/leaderelection"
Expand Down Expand Up @@ -70,6 +71,7 @@ func main() {
httpRetry int
clientOptions client.Options
logOptions logger.Options
aclOptions acl.Options
leaderElectionOptions leaderelection.Options
)

Expand All @@ -83,6 +85,7 @@ func main() {
flag.IntVar(&httpRetry, "http-retry", 9, "The maximum number of retries when failing to fetch artifacts over HTTP.")
clientOptions.BindFlags(flag.CommandLine)
logOptions.BindFlags(flag.CommandLine)
aclOptions.BindFlags(flag.CommandLine)
leaderElectionOptions.BindFlags(flag.CommandLine)
flag.Parse()

Expand Down Expand Up @@ -139,6 +142,7 @@ func main() {
EventRecorder: mgr.GetEventRecorderFor(controllerName),
ExternalEventRecorder: eventRecorder,
MetricsRecorder: metricsRecorder,
NoCrossNamespaceRef: aclOptions.NoCrossNamespaceRefs,
}).SetupWithManager(mgr, controllers.HelmReleaseReconcilerOptions{
MaxConcurrentReconciles: concurrent,
DependencyRequeueInterval: requeueDependency,
Expand Down

0 comments on commit bf0a366

Please sign in to comment.