Skip to content

Commit

Permalink
feat(sourceNamespace): Regex Support
Browse files Browse the repository at this point in the history
Signed-off-by: Arthur <[email protected]>
  • Loading branch information
ArthurVardevanyan committed Aug 5, 2024
1 parent 2db3840 commit 94f7c5b
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 3 deletions.
10 changes: 8 additions & 2 deletions docs/operator-manual/app-any-namespace.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ In order for an application to be managed and reconciled outside the Argo CD's c

In order to enable this feature, the Argo CD administrator must reconfigure the `argocd-server` and `argocd-application-controller` workloads to add the `--application-namespaces` parameter to the container's startup command.

The `--application-namespaces` parameter takes a comma-separated list of namespaces where `Applications` are to be allowed in. Each entry of the list supports shell-style wildcards such as `*`, so for example the entry `app-team-*` would match `app-team-one` and `app-team-two`. To enable all namespaces on the cluster where Argo CD is running on, you can just specify `*`, i.e. `--application-namespaces=*`.
The `--application-namespaces` parameter takes a comma-separated list of namespaces where `Applications` are to be allowed in. Each entry of the list supports,

- shell-style wildcards such as `*`, so for example the entry `app-team-*` would match `app-team-one` and `app-team-two`. To enable all namespaces on the cluster where Argo CD is running on, you can just specify `*`, i.e. `--application-namespaces=*`.
- regex, requires wrapping the string in ```/```, example to allow all namespaces except a particular one: ```/^((?!not-allowed).)*$/```.

The startup parameters for both, the `argocd-server` and the `argocd-application-controller` can also be conveniently set up and kept in sync by specifying the `application.namespaces` settings in the `argocd-cmd-params-cm` ConfigMap _instead_ of changing the manifests for the respective workloads. For example:

```yaml
Expand Down Expand Up @@ -113,7 +116,10 @@ If an Application in `namespace-two` would set their `.spec.project` to `project

Also, the Argo CD API will enforce these constraints, regardless of the Argo CD RBAC permissions.

The `.spec.sourceNamespaces` field of the `AppProject` is a list that can contain an arbitrary amount of namespaces, and each entry supports shell-style wildcard, so that you can allow namespaces with patterns like `team-one-*`.
The `.spec.sourceNamespaces` field of the `AppProject` is a list that can contain an arbitrary amount of namespaces, each entry supports:

- shell-style wildcard, so that you can allow namespaces with patterns like ```team-one-*```
- regex, requires wrapping the string in ```/```, example to allow all namespaces except a particular one: ```/^((?!not-allowed).)*$/```.

!!! warning
Do not add user controlled namespaces in the `.spec.sourceNamespaces` field of any privileged AppProject like the `default` project. Always make sure that the AppProject follows the principle of granting least required privileges. Never grant access to the `argocd` namespace within the AppProject.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.11.2
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/evanphx/json-patch/v5 v5.8.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dlclark/regexp2 v1.11.2 h1:/u628IuisSTwri5/UKloiIsH8+qF2Pu7xEQX+yIKg68=
github.com/dlclark/regexp2 v1.11.2/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c=
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
Expand Down
13 changes: 12 additions & 1 deletion util/glob/list.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
package glob

import (
"strings"

"github.com/argoproj/argo-cd/v2/util/regex"
)

// MatchStringInList will return true if item is contained in list. If
// exactMatch is set to false, list may contain globs to be matched.
func MatchStringInList(list []string, item string, exactMatch bool) bool {
for _, ll := range list {
if item == ll || (!exactMatch && Match(ll, item)) {
// If string is wrapped in "/", assume it is a regular expression.
if !exactMatch && strings.HasPrefix(ll, "/") && strings.HasSuffix(ll, "/") {
if regex.Match(ll[1:len(ll)-1], item) {
return true
}
} else if item == ll || (!exactMatch && Match(ll, item)) {
return true
}
}
Expand Down
20 changes: 20 additions & 0 deletions util/regex/regex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package regex

import (
"github.com/dlclark/regexp2"
log "github.com/sirupsen/logrus"
)

func Match(pattern, text string) bool {
compiledRegex, err := regexp2.Compile(pattern, 0)
if err != nil {
log.Warnf("failed to compile pattern %s due to error %v", pattern, err)
return false
}
regexMatch, err := compiledRegex.MatchString(text)
if err != nil {
log.Warnf("failed to match pattern %s due to error %v", pattern, err)
return false
}
return regexMatch
}
14 changes: 14 additions & 0 deletions util/security/application_namespaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ func Test_IsNamespaceEnabled(t *testing.T) {
[]string{"allowed"},
false,
},
{
"match everything but specified word: fail",
"disallowed",
"argocd",
[]string{"/^((?!disallowed).)*$/"},
false,
},
{
"match everything but specified word: pass",
"allowed",
"argocd",
[]string{"/^((?!disallowed).)*$/"},
true,
},
}

for _, tc := range testCases {
Expand Down

0 comments on commit 94f7c5b

Please sign in to comment.