Skip to content

Commit

Permalink
feat: dangerousToNamespacesSelector
Browse files Browse the repository at this point in the history
Signed-off-by: devthejo <jo@surikat.pro>
  • Loading branch information
devthejo committed Jul 13, 2023
1 parent 5d98b5e commit c7b0284
Show file tree
Hide file tree
Showing 12 changed files with 587 additions and 65 deletions.
2 changes: 1 addition & 1 deletion cmd/controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func main() {

{
secretExports := sharing.NewSecretExportsWarmedUp(
sharing.NewSecretExports(log.WithName("secretexports")))
sharing.NewSecretExports(mgr.GetClient(), log.WithName("secretexports")))

secretExportReconciler := sharing.NewSecretExportReconciler(
mgr.GetClient(), secretExports, log.WithName("secexp"))
Expand Down
24 changes: 24 additions & 0 deletions config/package-bundle/config/crds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,30 @@ spec:
items:
type: string
type: array
dangerousToNamespacesSelector:
type: array
items:
properties:
key:
type: string
description: Property to target the resource for the match. It supports dot notation.
operator:
type: string
description: Type of comparison.
enum:
- In
- NotIn
- Exists
- DoesNotExist
values:
description: Values to match on the resource key using the comparison operator.
type: array
items:
type: string
type: object
required:
- key
- operator
type: object
status:
properties:
Expand Down
34 changes: 33 additions & 1 deletion docs/secret-export.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ apiVersion: v1
kind: Namespace
metadata:
name: user2
---
apiVersion: v1
kind: Namespace
metadata:
name: user3
annotations:
field.cattle.io/projectId: "cluster1:project1"

#! generate user-password secret upon creation
---
Expand All @@ -29,7 +36,7 @@ metadata:
name: user-password
namespace: user1

#! offer user-password to user2 namespace
#! offer user-password to user2 namespace and namespace with specified annotations (in this case user3)
---
apiVersion: secretgen.carvel.dev/v1alpha1
kind: SecretExport
Expand All @@ -38,6 +45,10 @@ metadata:
namespace: user1
spec:
toNamespace: user2
dangerousToNamespacesSelector:
- key: "metadata.annotations['field\\.cattle\\.io/projectId']"
operator: In
value: "cluster1:project1"

#! allow user-password to be created in user2 namespace
---
Expand All @@ -48,6 +59,17 @@ metadata:
namespace: user2
spec:
fromNamespace: user1

#! allow user-password to be created in namespace user3
---
apiVersion: secretgen.carvel.dev/v1alpha1
kind: SecretImport
metadata:
name: user-password
namespace: user3
spec:
fromNamespace: user1

```

Above configuration results in a `user-password` Secret created within `user2` namespace:
Expand Down Expand Up @@ -75,6 +97,16 @@ SecretExport CRD allows to "offer" secrets for export.

- `toNamespace` (optional; string) Destination namespace for offer. Use `*` to indicate all namespaces.
- `toNamespaces` (optional; array of strings) List of destination namespaces for offer.
- `dangerousToNamespacesSelector` (optional; array of selector objects) List of matchers for destination namespaces. If multiple expressions are specified, all those expressions must evaluate to true for the selector to match a namespace. The selector object is composed as follows:
- `key` (required; string) Property to target on the resource for the match. Based on kubernetes JSONPath syntax.
- `operator` (required; enum string) Type of comparison. Must be one of `In`, `NotIn`, `Exists`, `DoesNotExist`.
Operator explanations:
- In: Label's value must match one of the specified values.
- NotIn: Label's value must not match any of the specified values.
- Exists: Namespace must include a label with the specified key (the value isn't relevant). When using this operator, the values field should not be specified.
- DoesNotExist: Namespace must not include a label with the specified key. The values property must not be specified.

- `values` (optional; array if string) Values to match on the resource key using the comparison operator.

### SecretImport

Expand Down
30 changes: 30 additions & 0 deletions examples/secret-export.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,33 @@ metadata:
namespace: user3
spec:
fromNamespace: user1

#! export user-password-multi secret from user1 to namespaces containing specific annotations
---
apiVersion: secretgen.k14s.io/v1alpha1
kind: Password
metadata:
name: scoped-user-password-multi
namespace: user1
---
apiVersion: secretgen.carvel.dev/v1alpha1
kind: SecretExport
metadata:
name: scoped-user-password-multi
namespace: user1
spec:
dangerousToNamespacesSelector:
- key: "metadata.annotations['field\\.cattle\\.io/projectId']"
operator: In
value: "cluster1:project1"
---
apiVersion: secretgen.carvel.dev/v1alpha1
kind: SecretImport
metadata:
name: scoped-user-password-multi
namespace: user2
annotations:
field.cattle.io/projectId: "cluster1:project1"
spec:
fromNamespace: user1

37 changes: 35 additions & 2 deletions pkg/apis/secretgen2/v1alpha1/secret_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,31 @@ type SecretExportList struct {
Items []SecretExport `json:"items"`
}

// SelectorOperator is a part of SelectorMatchField
type SelectorOperator string

// SelectorOperator values
const (
SelectorOperatorIn SelectorOperator = "In"
SelectorOperatorNotIn = "NotIn"
SelectorOperatorExists = "Exists"
SelectorOperatorDoesNotExist = "DoesNotExist"
)

// SelectorMatchField is a selector field to match against namespace definition
type SelectorMatchField struct {
Key string `json:"key,omitempty"`
Operator SelectorOperator `json:"operator,omitempty"`
Values []string `json:"values,omitempty"`
}

type SecretExportSpec struct {
// +optional
ToNamespace string `json:"toNamespace,omitempty"`
// +optional
ToNamespaces []string `json:"toNamespaces,omitempty"`
// +optional
ToNamespacesSelector []SelectorMatchField `json:"dangerousToNamespacesSelector,omitempty"`
}

type SecretExportStatus struct {
Expand All @@ -68,15 +88,28 @@ func (e SecretExport) Validate() error {
var errs []error

toNses := e.StaticToNamespaces()
toSmf := e.Spec.ToNamespacesSelector

if len(toNses) == 0 {
errs = append(errs, fmt.Errorf("Expected to have at least one non-empty to namespace"))
if len(toNses) == 0 && len(toSmf) == 0 {
errs = append(errs, fmt.Errorf("Expected to have at least one non-empty to namespace or to namespace annotation"))
}
for _, ns := range toNses {
if len(ns) == 0 {
errs = append(errs, fmt.Errorf("Expected to namespace to be non-empty"))
}
}
for _, s := range toSmf {
switch s.Operator {
case SelectorOperatorIn, SelectorOperatorNotIn:
if len(s.Values) == 0 {
errs = append(errs, fmt.Errorf("Values must be specified when `operator` is 'In' or 'NotIn'"))
}
case SelectorOperatorExists, SelectorOperatorDoesNotExist:
if len(s.Values) > 0 {
errs = append(errs, fmt.Errorf("Values may not be specified when `operator` is 'Exists' or 'DoesNotExist'"))
}
}
}

return combinedErrs("Validation errors", errs)
}
2 changes: 1 addition & 1 deletion pkg/sharing/import_secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func secretImportFor(sourceSecret corev1.Secret) sg2v1alpha1.SecretImport {

func importReconcilers(objects ...runtime.Object) (secretExportReconciler *sharing.SecretExportReconciler, secretImportReconciler *sharing.SecretImportReconciler, k8sClient client.Client) {
k8sClient = fakeClient.NewFakeClient(objects...)
secretExports := sharing.NewSecretExportsWarmedUp(sharing.NewSecretExports(testLogr))
secretExports := sharing.NewSecretExportsWarmedUp(sharing.NewSecretExports(k8sClient, testLogr))
secretExportReconciler = sharing.NewSecretExportReconciler(k8sClient, secretExports, testLogr)
secretExports.WarmUpFunc = secretExportReconciler.WarmUp
secretImportReconciler = sharing.NewSecretImportReconciler(k8sClient, secretExports, testLogr)
Expand Down
2 changes: 1 addition & 1 deletion pkg/sharing/placeholder_secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func Test_SecretReconciler_updatesStatus(t *testing.T) {
}
func placeholderReconcilers(objects ...runtime.Object) (secretExportReconciler *sharing.SecretExportReconciler, secretReconciler *sharing.SecretReconciler, k8sClient client.Client) {
k8sClient = fakeClient.NewFakeClient(objects...)
secretExports := sharing.NewSecretExportsWarmedUp(sharing.NewSecretExports(testLogr))
secretExports := sharing.NewSecretExportsWarmedUp(sharing.NewSecretExports(k8sClient, testLogr))
secretExportReconciler = sharing.NewSecretExportReconciler(k8sClient, secretExports, testLogr)
secretExports.WarmUpFunc = secretExportReconciler.WarmUp
secretReconciler = sharing.NewSecretReconciler(k8sClient, secretExports, testLogr)
Expand Down
Loading

0 comments on commit c7b0284

Please sign in to comment.