From 36e76eba4f6181f3103d85698ef0d804334ac49b Mon Sep 17 00:00:00 2001 From: Arthur Date: Wed, 10 Jul 2024 16:55:28 +0000 Subject: [PATCH] feat(sourceNamespace): Exclusion Signed-off-by: Arthur --- .../commands/argocd_application_controller.go | 3 + .../commands/controller.go | 4 +- cmd/argocd-server/commands/argocd_server.go | 125 +++++++++--------- controller/appcontroller.go | 5 +- controller/appcontroller_test.go | 1 + docs/operator-manual/notifications/index.md | 2 +- .../argocd-application-controller.md | 1 + .../server-commands/argocd-server.md | 1 + .../controller/controller.go | 9 +- .../controller/controller_test.go | 2 + server/application/application.go | 69 +++++----- server/application/application_test.go | 2 + server/application/terminal.go | 2 +- server/applicationset/applicationset.go | 4 +- server/badge/badge.go | 2 +- server/server.go | 60 +++++---- util/security/application_namespaces.go | 4 +- util/security/application_namespaces_test.go | 2 +- 18 files changed, 161 insertions(+), 137 deletions(-) diff --git a/cmd/argocd-application-controller/commands/argocd_application_controller.go b/cmd/argocd-application-controller/commands/argocd_application_controller.go index 5d7fd803e7aca2..dd0eb00272ecbd 100644 --- a/cmd/argocd-application-controller/commands/argocd_application_controller.go +++ b/cmd/argocd-application-controller/commands/argocd_application_controller.go @@ -69,6 +69,7 @@ func NewCommand() *cobra.Command { otlpHeaders map[string]string otlpAttrs []string applicationNamespaces []string + applicationNamespacesIgnored []string persistResourceHealth bool shardingAlgorithm string enableDynamicClusterDistribution bool @@ -168,6 +169,7 @@ func NewCommand() *cobra.Command { persistResourceHealth, clusterSharding, applicationNamespaces, + applicationNamespacesIgnored, &workqueueRateLimit, serverSideDiff, enableDynamicClusterDistribution, @@ -219,6 +221,7 @@ func NewCommand() *cobra.Command { command.Flags().StringToStringVar(&otlpHeaders, "otlp-headers", env.ParseStringToStringFromEnv("ARGOCD_APPLICATION_CONTROLLER_OTLP_HEADERS", map[string]string{}, ","), "List of OpenTelemetry collector extra headers sent with traces, headers are comma-separated key-value pairs(e.g. key1=value1,key2=value2)") command.Flags().StringSliceVar(&otlpAttrs, "otlp-attrs", env.StringsFromEnv("ARGOCD_APPLICATION_CONTROLLER_OTLP_ATTRS", []string{}, ","), "List of OpenTelemetry collector extra attrs when send traces, each attribute is separated by a colon(e.g. key:value)") command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces that applications are allowed to be reconciled from") + command.Flags().StringSliceVar(&applicationNamespacesIgnored, "application-namespaces-ignored", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES_IGNORED", []string{}, ","), "List of additional namespaces where application resources should be ignored") command.Flags().BoolVar(&persistResourceHealth, "persist-resource-health", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_PERSIST_RESOURCE_HEALTH", true), "Enables storing the managed resources health in the Application CRD") command.Flags().StringVar(&shardingAlgorithm, "sharding-method", env.StringFromEnv(common.EnvControllerShardingAlgorithm, common.DefaultShardingAlgorithm), "Enables choice of sharding method. Supported sharding methods are : [legacy, round-robin, consistent-hashing] ") // global queue rate limit config diff --git a/cmd/argocd-notification/commands/controller.go b/cmd/argocd-notification/commands/controller.go index a2ae2cb7e4c514..bbc3003ee13a1b 100644 --- a/cmd/argocd-notification/commands/controller.go +++ b/cmd/argocd-notification/commands/controller.go @@ -56,6 +56,7 @@ func NewCommand() *cobra.Command { configMapName string secretName string applicationNamespaces []string + applicationNamespacesIgnored []string selfServiceNotificationEnabled bool ) command := cobra.Command{ @@ -140,7 +141,7 @@ func NewCommand() *cobra.Command { log.Infof("serving metrics on port %d", metricsPort) log.Infof("loading configuration %d", metricsPort) - ctrl := notificationscontroller.NewController(k8sClient, dynamicClient, argocdService, namespace, applicationNamespaces, appLabelSelector, registry, secretName, configMapName, selfServiceNotificationEnabled) + ctrl := notificationscontroller.NewController(k8sClient, dynamicClient, argocdService, namespace, applicationNamespaces, applicationNamespacesIgnored, appLabelSelector, registry, secretName, configMapName, selfServiceNotificationEnabled) err = ctrl.Init(ctx) if err != nil { return fmt.Errorf("failed to initialize controller: %w", err) @@ -164,6 +165,7 @@ func NewCommand() *cobra.Command { command.Flags().StringVar(&configMapName, "config-map-name", "argocd-notifications-cm", "Set notifications ConfigMap name") command.Flags().StringVar(&secretName, "secret-name", "argocd-notifications-secret", "Set notifications Secret name") command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces that this controller should send notifications for") + command.Flags().StringSliceVar(&applicationNamespacesIgnored, "application-namespaces-ignored", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES_IGNORED", []string{}, ","), "List of additional namespaces where application resources should be ignored") command.Flags().BoolVar(&selfServiceNotificationEnabled, "self-service-notification-enabled", env.ParseBoolFromEnv("ARGOCD_NOTIFICATION_CONTROLLER_SELF_SERVICE_NOTIFICATION_ENABLED", false), "Allows the Argo CD notification controller to pull notification config from the namespace that the resource is in. This is useful for self-service notification.") return &command } diff --git a/cmd/argocd-server/commands/argocd_server.go b/cmd/argocd-server/commands/argocd_server.go index 552de22909bea6..e982037681b4e0 100644 --- a/cmd/argocd-server/commands/argocd_server.go +++ b/cmd/argocd-server/commands/argocd_server.go @@ -50,39 +50,40 @@ var ( // NewCommand returns a new instance of an argocd command func NewCommand() *cobra.Command { var ( - redisClient *redis.Client - insecure bool - listenHost string - listenPort int - metricsHost string - metricsPort int - otlpAddress string - otlpInsecure bool - otlpHeaders map[string]string - otlpAttrs []string - glogLevel int - clientConfig clientcmd.ClientConfig - repoServerTimeoutSeconds int - baseHRef string - rootPath string - repoServerAddress string - dexServerAddress string - disableAuth bool - contentTypes string - enableGZip bool - tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error) - cacheSrc func() (*servercache.Cache, error) - repoServerCacheSrc func() (*reposervercache.Cache, error) - frameOptions string - contentSecurityPolicy string - repoServerPlaintext bool - repoServerStrictTLS bool - dexServerPlaintext bool - dexServerStrictTLS bool - staticAssetsDir string - applicationNamespaces []string - enableProxyExtension bool - webhookParallelism int + redisClient *redis.Client + insecure bool + listenHost string + listenPort int + metricsHost string + metricsPort int + otlpAddress string + otlpInsecure bool + otlpHeaders map[string]string + otlpAttrs []string + glogLevel int + clientConfig clientcmd.ClientConfig + repoServerTimeoutSeconds int + baseHRef string + rootPath string + repoServerAddress string + dexServerAddress string + disableAuth bool + contentTypes string + enableGZip bool + tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error) + cacheSrc func() (*servercache.Cache, error) + repoServerCacheSrc func() (*reposervercache.Cache, error) + frameOptions string + contentSecurityPolicy string + repoServerPlaintext bool + repoServerStrictTLS bool + dexServerPlaintext bool + dexServerStrictTLS bool + staticAssetsDir string + applicationNamespaces []string + applicationNamespacesIgnored []string + enableProxyExtension bool + webhookParallelism int // ApplicationSet enableNewGitFileGlobbing bool @@ -195,34 +196,35 @@ func NewCommand() *cobra.Command { } argoCDOpts := server.ArgoCDServerOpts{ - Insecure: insecure, - ListenPort: listenPort, - ListenHost: listenHost, - MetricsPort: metricsPort, - MetricsHost: metricsHost, - Namespace: namespace, - BaseHRef: baseHRef, - RootPath: rootPath, - DynamicClientset: dynamicClient, - KubeControllerClientset: controllerClient, - KubeClientset: kubeclientset, - AppClientset: appClientSet, - RepoClientset: repoclientset, - DexServerAddr: dexServerAddress, - DexTLSConfig: dexTlsConfig, - DisableAuth: disableAuth, - ContentTypes: contentTypesList, - EnableGZip: enableGZip, - TLSConfigCustomizer: tlsConfigCustomizer, - Cache: cache, - RepoServerCache: repoServerCache, - XFrameOptions: frameOptions, - ContentSecurityPolicy: contentSecurityPolicy, - RedisClient: redisClient, - StaticAssetsDir: staticAssetsDir, - ApplicationNamespaces: applicationNamespaces, - EnableProxyExtension: enableProxyExtension, - WebhookParallelism: webhookParallelism, + Insecure: insecure, + ListenPort: listenPort, + ListenHost: listenHost, + MetricsPort: metricsPort, + MetricsHost: metricsHost, + Namespace: namespace, + BaseHRef: baseHRef, + RootPath: rootPath, + DynamicClientset: dynamicClient, + KubeControllerClientset: controllerClient, + KubeClientset: kubeclientset, + AppClientset: appClientSet, + RepoClientset: repoclientset, + DexServerAddr: dexServerAddress, + DexTLSConfig: dexTlsConfig, + DisableAuth: disableAuth, + ContentTypes: contentTypesList, + EnableGZip: enableGZip, + TLSConfigCustomizer: tlsConfigCustomizer, + Cache: cache, + RepoServerCache: repoServerCache, + XFrameOptions: frameOptions, + ContentSecurityPolicy: contentSecurityPolicy, + RedisClient: redisClient, + StaticAssetsDir: staticAssetsDir, + ApplicationNamespaces: applicationNamespaces, + ApplicationNamespacesIgnored: applicationNamespacesIgnored, + EnableProxyExtension: enableProxyExtension, + WebhookParallelism: webhookParallelism, } appsetOpts := server.ApplicationSetOpts{ @@ -295,6 +297,7 @@ func NewCommand() *cobra.Command { command.Flags().BoolVar(&dexServerPlaintext, "dex-server-plaintext", env.ParseBoolFromEnv("ARGOCD_SERVER_DEX_SERVER_PLAINTEXT", false), "Use a plaintext client (non-TLS) to connect to dex server") command.Flags().BoolVar(&dexServerStrictTLS, "dex-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_SERVER_DEX_SERVER_STRICT_TLS", false), "Perform strict validation of TLS certificates when connecting to dex server") command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces where application resources can be managed in") + command.Flags().StringSliceVar(&applicationNamespacesIgnored, "application-namespaces-ignored", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES_IGNORED", []string{}, ","), "List of additional namespaces where application resources should be ignored") command.Flags().BoolVar(&enableProxyExtension, "enable-proxy-extension", env.ParseBoolFromEnv("ARGOCD_SERVER_ENABLE_PROXY_EXTENSION", false), "Enable Proxy Extension feature") command.Flags().IntVar(&webhookParallelism, "webhook-parallelism-limit", env.ParseNumFromEnv("ARGOCD_SERVER_WEBHOOK_PARALLELISM_LIMIT", 50, 1, 1000), "Number of webhook requests processed concurrently") diff --git a/controller/appcontroller.go b/controller/appcontroller.go index 0d92e94b7a878a..cf5ec9b0160bbf 100644 --- a/controller/appcontroller.go +++ b/controller/appcontroller.go @@ -140,6 +140,7 @@ type ApplicationController struct { clusterSharding sharding.ClusterShardingCache projByNameCache sync.Map applicationNamespaces []string + applicationNamespacesIgnored []string ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts // dynamicClusterDistributionEnabled if disabled deploymentInformer is never initialized @@ -168,6 +169,7 @@ func NewApplicationController( persistResourceHealth bool, clusterSharding sharding.ClusterShardingCache, applicationNamespaces []string, + applicationNamespacesIgnored []string, rateLimiterConfig *ratelimiter.AppControllerRateLimiterConfig, serverSideDiff bool, dynamicClusterDistributionEnabled bool, @@ -202,6 +204,7 @@ func NewApplicationController( clusterSharding: clusterSharding, projByNameCache: sync.Map{}, applicationNamespaces: applicationNamespaces, + applicationNamespacesIgnored: applicationNamespacesIgnored, dynamicClusterDistributionEnabled: dynamicClusterDistributionEnabled, ignoreNormalizerOpts: ignoreNormalizerOpts, } @@ -2087,7 +2090,7 @@ func (ctrl *ApplicationController) shouldSelfHeal(app *appv1.Application) (bool, // isAppNamespaceAllowed returns whether the application is allowed in the // namespace it's residing in. func (ctrl *ApplicationController) isAppNamespaceAllowed(app *appv1.Application) bool { - return app.Namespace == ctrl.namespace || glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, false) + return app.Namespace == ctrl.namespace || (glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, false) && !glob.MatchStringInList(ctrl.applicationNamespacesIgnored, app.Namespace, false)) } func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool { diff --git a/controller/appcontroller_test.go b/controller/appcontroller_test.go index 52d9ba9f98887b..df2f9b05c2f115 100644 --- a/controller/appcontroller_test.go +++ b/controller/appcontroller_test.go @@ -159,6 +159,7 @@ func newFakeController(data *fakeData, repoErr error) *ApplicationController { true, nil, data.applicationNamespaces, + []string{}, nil, false, false, diff --git a/docs/operator-manual/notifications/index.md b/docs/operator-manual/notifications/index.md index 002f67249c6162..e774af351ac1cb 100644 --- a/docs/operator-manual/notifications/index.md +++ b/docs/operator-manual/notifications/index.md @@ -55,7 +55,7 @@ for their Argo CD applications. For example, the end-user can configure notifica This feature is based on applications in any namespace. See [applications in any namespace](../app-any-namespace.md) page for more information. In order to enable this feature, the Argo CD administrator must reconfigure the argocd-notification-controller workloads to add `--application-namespaces` and `--self-service-notification-enabled` parameters to the container's startup command. -`--application-namespaces` controls the list of namespaces that Argo CD applications are in. `--self-service-notification-enabled` turns on this feature. +`--application-namespaces` controls the list of namespaces that Argo CD applications are in. `--self-service-notification-enabled` turns on this feature. If some additional namespaces need to excluded that are within the previous selection, `--application-namespaces-ignored` can be used. The startup parameters for both can also be conveniently set up and kept in sync by specifying the `application.namespaces` and `notificationscontroller.selfservice.enabled` in the argocd-cmd-params-cm ConfigMap instead of changing the manifests for the respective workloads. For example: diff --git a/docs/operator-manual/server-commands/argocd-application-controller.md b/docs/operator-manual/server-commands/argocd-application-controller.md index 930dfa414751c3..d6446bd5a3d022 100644 --- a/docs/operator-manual/server-commands/argocd-application-controller.md +++ b/docs/operator-manual/server-commands/argocd-application-controller.md @@ -20,6 +20,7 @@ argocd-application-controller [flags] --app-resync-jitter int Maximum time period in seconds to add as a delay jitter for application resync. --app-state-cache-expiration duration Cache expiration for app state (default 1h0m0s) --application-namespaces strings List of additional namespaces that applications are allowed to be reconciled from + --application-namespaces-ignored strings List of additional namespaces where application resources should be ignored --as string Username to impersonate for the operation --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. --as-uid string UID to impersonate for the operation diff --git a/docs/operator-manual/server-commands/argocd-server.md b/docs/operator-manual/server-commands/argocd-server.md index 2f022f3da2be08..551aa3f93e6a93 100644 --- a/docs/operator-manual/server-commands/argocd-server.md +++ b/docs/operator-manual/server-commands/argocd-server.md @@ -29,6 +29,7 @@ argocd-server [flags] --api-content-types string Semicolon separated list of allowed content types for non GET api requests. Any content type is allowed if empty. (default "application/json") --app-state-cache-expiration duration Cache expiration for app state (default 1h0m0s) --application-namespaces strings List of additional namespaces where application resources can be managed in + --application-namespaces-ignored strings List of additional namespaces where application resources should be ignored --appset-allowed-scm-providers strings The list of allowed custom SCM provider API URLs. This restriction does not apply to SCM or PR generators which do not accept a custom API URL. (Default: Empty = all) --appset-enable-new-git-file-globbing Enable new globbing in Git files generator. --appset-enable-scm-providers Enable retrieving information from SCM providers, used by the SCM and PR generators (Default: true) (default true) diff --git a/notification_controller/controller/controller.go b/notification_controller/controller/controller.go index 1bc3e73a6fbd71..a2513b4a86a6ce 100644 --- a/notification_controller/controller/controller.go +++ b/notification_controller/controller/controller.go @@ -60,6 +60,7 @@ func NewController( argocdService service.Service, namespace string, applicationNamespaces []string, + applicationNamespacesIgnored []string, appLabelSelector string, registry *controller.MetricsRegistry, secretName string, @@ -74,8 +75,8 @@ func NewController( if len(applicationNamespaces) == 0 { appClient = namespaceableAppClient.Namespace(namespace) } - appInformer := newInformer(appClient, namespace, applicationNamespaces, appLabelSelector) - appProjInformer := newInformer(newAppProjClient(client, namespace), namespace, []string{namespace}, "") + appInformer := newInformer(appClient, namespace, applicationNamespaces, applicationNamespacesIgnored, appLabelSelector) + appProjInformer := newInformer(newAppProjClient(client, namespace), namespace, []string{namespace}, applicationNamespacesIgnored, "") var notificationConfigNamespace string if selfServiceNotificationEnabled { notificationConfigNamespace = v1.NamespaceAll @@ -138,7 +139,7 @@ func (c *notificationController) alterDestinations(obj v1.Object, destinations s return destinations } -func newInformer(resClient dynamic.ResourceInterface, controllerNamespace string, applicationNamespaces []string, selector string) cache.SharedIndexInformer { +func newInformer(resClient dynamic.ResourceInterface, controllerNamespace string, applicationNamespaces []string, applicationNamespacesIgnored []string, selector string) cache.SharedIndexInformer { informer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { @@ -151,7 +152,7 @@ func newInformer(resClient dynamic.ResourceInterface, controllerNamespace string } newItems := []unstructured.Unstructured{} for _, res := range appList.Items { - if controllerNamespace == res.GetNamespace() || glob.MatchStringInList(applicationNamespaces, res.GetNamespace(), false) { + if controllerNamespace == res.GetNamespace() || (glob.MatchStringInList(applicationNamespaces, res.GetNamespace(), false && !glob.MatchStringInList(applicationNamespacesIgnored, res.GetNamespace(), false))) { newItems = append(newItems, res) } } diff --git a/notification_controller/controller/controller_test.go b/notification_controller/controller/controller_test.go index ca901cf2c1890c..7c131aa866387a 100644 --- a/notification_controller/controller/controller_test.go +++ b/notification_controller/controller/controller_test.go @@ -120,6 +120,7 @@ func TestInit(t *testing.T) { nil, "default", []string{}, + []string{}, appLabelSelector, nil, "my-secret", @@ -154,6 +155,7 @@ func TestInitTimeout(t *testing.T) { nil, "default", []string{}, + []string{}, appLabelSelector, nil, "my-secret", diff --git a/server/application/application.go b/server/application/application.go index af535ca6295c81..21d9efca257871 100644 --- a/server/application/application.go +++ b/server/application/application.go @@ -77,22 +77,23 @@ var ( // Server provides an Application service type Server struct { - ns string - kubeclientset kubernetes.Interface - appclientset appclientset.Interface - appLister applisters.ApplicationLister - appInformer cache.SharedIndexInformer - appBroadcaster Broadcaster - repoClientset apiclient.Clientset - kubectl kube.Kubectl - db db.ArgoDB - enf *rbac.Enforcer - projectLock sync.KeyLock - auditLogger *argo.AuditLogger - settingsMgr *settings.SettingsManager - cache *servercache.Cache - projInformer cache.SharedIndexInformer - enabledNamespaces []string + ns string + kubeclientset kubernetes.Interface + appclientset appclientset.Interface + appLister applisters.ApplicationLister + appInformer cache.SharedIndexInformer + appBroadcaster Broadcaster + repoClientset apiclient.Clientset + kubectl kube.Kubectl + db db.ArgoDB + enf *rbac.Enforcer + projectLock sync.KeyLock + auditLogger *argo.AuditLogger + settingsMgr *settings.SettingsManager + cache *servercache.Cache + projInformer cache.SharedIndexInformer + enabledNamespaces []string + enabledNamespacesIgnored []string } // NewServer returns a new instance of the Application service @@ -112,6 +113,7 @@ func NewServer( settingsMgr *settings.SettingsManager, projInformer cache.SharedIndexInformer, enabledNamespaces []string, + enabledNamespacesIgnored []string, ) (application.ApplicationServiceServer, AppResourceTreeFn) { if appBroadcaster == nil { appBroadcaster = &broadcasterHandler{} @@ -121,22 +123,23 @@ func NewServer( log.Error(err) } s := &Server{ - ns: namespace, - appclientset: appclientset, - appLister: appLister, - appInformer: appInformer, - appBroadcaster: appBroadcaster, - kubeclientset: kubeclientset, - cache: cache, - db: db, - repoClientset: repoClientset, - kubectl: kubectl, - enf: enf, - projectLock: projectLock, - auditLogger: argo.NewAuditLogger(namespace, kubeclientset, "argocd-server"), - settingsMgr: settingsMgr, - projInformer: projInformer, - enabledNamespaces: enabledNamespaces, + ns: namespace, + appclientset: appclientset, + appLister: appLister, + appInformer: appInformer, + appBroadcaster: appBroadcaster, + kubeclientset: kubeclientset, + cache: cache, + db: db, + repoClientset: repoClientset, + kubectl: kubectl, + enf: enf, + projectLock: projectLock, + auditLogger: argo.NewAuditLogger(namespace, kubeclientset, "argocd-server"), + settingsMgr: settingsMgr, + projInformer: projInformer, + enabledNamespaces: enabledNamespaces, + enabledNamespacesIgnored: enabledNamespacesIgnored, } return s, s.getAppResources } @@ -2671,7 +2674,7 @@ func (s *Server) appNamespaceOrDefault(appNs string) string { } func (s *Server) isNamespaceEnabled(namespace string) bool { - return security.IsNamespaceEnabled(namespace, s.ns, s.enabledNamespaces) + return security.IsNamespaceEnabled(namespace, s.ns, s.enabledNamespaces, s.enabledNamespacesIgnored) } // getProjectFromApplicationQuery gets the project names from a query. If the legacy "project" field was specified, use diff --git a/server/application/application_test.go b/server/application/application_test.go index 96bfeaf51221c2..616ef19053ba56 100644 --- a/server/application/application_test.go +++ b/server/application/application_test.go @@ -308,6 +308,7 @@ func newTestAppServerWithEnforcerConfigure(f func(*rbac.Enforcer), t *testing.T, settingsMgr, projInformer, []string{}, + []string{}, ) return server.(*Server) } @@ -488,6 +489,7 @@ func newTestAppServerWithEnforcerConfigureWithBenchmark(f func(*rbac.Enforcer), settingsMgr, projInformer, []string{}, + []string{}, ) return server.(*Server) } diff --git a/server/application/terminal.go b/server/application/terminal.go index b0fad379e8ae60..5b8f86a238d47e 100644 --- a/server/application/terminal.go +++ b/server/application/terminal.go @@ -136,7 +136,7 @@ func (s *terminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ns = s.namespace } - if !security.IsNamespaceEnabled(ns, s.namespace, s.enabledNamespaces) { + if !security.IsNamespaceEnabled(ns, s.namespace, s.enabledNamespaces, []string{}) { http.Error(w, security.NamespaceNotPermittedError(ns).Error(), http.StatusForbidden) return } diff --git a/server/applicationset/applicationset.go b/server/applicationset/applicationset.go index a66173384e8c1a..138b717848b3a1 100644 --- a/server/applicationset/applicationset.go +++ b/server/applicationset/applicationset.go @@ -153,7 +153,7 @@ func (s *Server) List(ctx context.Context, q *applicationset.ApplicationSetListQ for _, a := range appsets { // Skip any application that is neither in the conrol plane's namespace // nor in the list of enabled namespaces. - if !security.IsNamespaceEnabled(a.Namespace, s.ns, s.enabledNamespaces) { + if !security.IsNamespaceEnabled(a.Namespace, s.ns, s.enabledNamespaces, []string{}) { continue } @@ -479,5 +479,5 @@ func (s *Server) appsetNamespaceOrDefault(appNs string) string { } func (s *Server) isNamespaceEnabled(namespace string) bool { - return security.IsNamespaceEnabled(namespace, s.ns, s.enabledNamespaces) + return security.IsNamespaceEnabled(namespace, s.ns, s.enabledNamespaces, []string{}) } diff --git a/server/badge/badge.go b/server/badge/badge.go index bc599e61ca0b27..5dd3a45310f901 100644 --- a/server/badge/badge.go +++ b/server/badge/badge.go @@ -109,7 +109,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { reqNs := "" if ns, ok := r.URL.Query()["namespace"]; ok && enabled { if argo.IsValidNamespaceName(ns[0]) { - if security.IsNamespaceEnabled(ns[0], h.namespace, h.enabledNamespaces) { + if security.IsNamespaceEnabled(ns[0], h.namespace, h.enabledNamespaces, []string{}) { reqNs = ns[0] } else { notFound = true diff --git a/server/server.go b/server/server.go index 23520ee8c90fc8..6ca7a291242bb8 100644 --- a/server/server.go +++ b/server/server.go @@ -201,34 +201,35 @@ type ArgoCDServer struct { } type ArgoCDServerOpts struct { - DisableAuth bool - ContentTypes []string - EnableGZip bool - Insecure bool - StaticAssetsDir string - ListenPort int - ListenHost string - MetricsPort int - MetricsHost string - Namespace string - DexServerAddr string - DexTLSConfig *dexutil.DexTLSConfig - BaseHRef string - RootPath string - DynamicClientset dynamic.Interface - KubeControllerClientset client.Client - KubeClientset kubernetes.Interface - AppClientset appclientset.Interface - RepoClientset repoapiclient.Clientset - Cache *servercache.Cache - RepoServerCache *repocache.Cache - RedisClient *redis.Client - TLSConfigCustomizer tlsutil.ConfigCustomizer - XFrameOptions string - ContentSecurityPolicy string - ApplicationNamespaces []string - EnableProxyExtension bool - WebhookParallelism int + DisableAuth bool + ContentTypes []string + EnableGZip bool + Insecure bool + StaticAssetsDir string + ListenPort int + ListenHost string + MetricsPort int + MetricsHost string + Namespace string + DexServerAddr string + DexTLSConfig *dexutil.DexTLSConfig + BaseHRef string + RootPath string + DynamicClientset dynamic.Interface + KubeControllerClientset client.Client + KubeClientset kubernetes.Interface + AppClientset appclientset.Interface + RepoClientset repoapiclient.Clientset + Cache *servercache.Cache + RepoServerCache *repocache.Cache + RedisClient *redis.Client + TLSConfigCustomizer tlsutil.ConfigCustomizer + XFrameOptions string + ContentSecurityPolicy string + ApplicationNamespaces []string + ApplicationNamespacesIgnored []string + EnableProxyExtension bool + WebhookParallelism int } type ApplicationSetOpts struct { @@ -878,7 +879,8 @@ func newArgoCDServiceSet(a *ArgoCDServer) *ArgoCDServiceSet { projectLock, a.settingsMgr, a.projInformer, - a.ApplicationNamespaces) + a.ApplicationNamespaces, + a.ApplicationNamespacesIgnored) applicationSetService := applicationset.NewServer( a.db, diff --git a/util/security/application_namespaces.go b/util/security/application_namespaces.go index 2ef5edea33a7fc..61e5d6efc524d8 100644 --- a/util/security/application_namespaces.go +++ b/util/security/application_namespaces.go @@ -6,8 +6,8 @@ import ( "github.com/argoproj/argo-cd/v2/util/glob" ) -func IsNamespaceEnabled(namespace string, serverNamespace string, enabledNamespaces []string) bool { - return namespace == serverNamespace || glob.MatchStringInList(enabledNamespaces, namespace, false) +func IsNamespaceEnabled(namespace string, serverNamespace string, enabledNamespaces []string, enabledNamespacesIgnored []string) bool { + return namespace == serverNamespace || (glob.MatchStringInList(enabledNamespaces, namespace, false) && !glob.MatchStringInList(enabledNamespacesIgnored, namespace, false)) } func NamespaceNotPermittedError(namespace string) error { diff --git a/util/security/application_namespaces_test.go b/util/security/application_namespaces_test.go index a2a5292385db48..107c972235d3fa 100644 --- a/util/security/application_namespaces_test.go +++ b/util/security/application_namespaces_test.go @@ -55,7 +55,7 @@ func Test_IsNamespaceEnabled(t *testing.T) { tcc := tc t.Run(tcc.name, func(t *testing.T) { t.Parallel() - result := IsNamespaceEnabled(tcc.namespace, tcc.serverNamespace, tcc.enabledNamespaces) + result := IsNamespaceEnabled(tcc.namespace, tcc.serverNamespace, tcc.enabledNamespaces, []string{}) assert.Equal(t, tcc.expectedResult, result) }) }