Skip to content

Commit

Permalink
fix: everything according to feedback
Browse files Browse the repository at this point in the history
Signed-off-by: devthejo <jo@surikat.pro>
  • Loading branch information
devthejo committed Jul 10, 2023
1 parent 64fc04d commit e849c32
Show file tree
Hide file tree
Showing 25 changed files with 139 additions and 5,427 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
2 changes: 1 addition & 1 deletion config/package-bundle/config/crds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ spec:
items:
type: string
type: array
toSelectorMatchFields:
dangerousToNamespacesSelector:
type: array
items:
properties:
Expand Down
6 changes: 3 additions & 3 deletions docs/secret-export.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ metadata:
namespace: user1
spec:
toNamespace: user2
toSelectorMatchFields:
- key: metadata.annotations.field\\.cattle\\.io/projectId:
dangerousToNamespacesSelector:
- key: "metadata.annotations['field\\.cattle\\.io/projectId']"
operator: In
value: "cluster1:project1"

Expand Down Expand Up @@ -97,7 +97,7 @@ 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.
- `toSelectorMatchFields` (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:
- `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. It's support dot notation from [GJSON syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md).
- `operator` (required; enum string) Type of comparison. Must be one of `In`, `NotIn`, `Exists`, `DoesNotExist`.
Operator explanations:
Expand Down
4 changes: 2 additions & 2 deletions examples/secret-export.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ metadata:
name: scoped-user-password-multi
namespace: user1
spec:
toSelectorMatchFields:
- key: metadata.annotations.field\\.cattle\\.io/projectId
dangerousToNamespacesSelector:
- key: "metadata.annotations['field\\.cattle\\.io/projectId']"
operator: In
value: "cluster1:project1"
---
Expand Down
4 changes: 0 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ require (
sigs.k8s.io/controller-tools v0.11.3
)

require github.com/tidwall/gjson v1.14.4

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
Expand Down Expand Up @@ -60,8 +58,6 @@ require (
github.com/prometheus/procfs v0.8.0 // indirect
github.com/spf13/cobra v1.6.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.24.0 // indirect
Expand Down
7 changes: 0 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -306,13 +306,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
Expand Down
8 changes: 4 additions & 4 deletions pkg/apis/secretgen2/v1alpha1/secret_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ const (

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

type SecretExportSpec struct {
Expand All @@ -63,7 +63,7 @@ type SecretExportSpec struct {
// +optional
ToNamespaces []string `json:"toNamespaces,omitempty"`
// +optional
ToSelectorMatchFields []SelectorMatchField `json:"toSelectorMatchFields,omitempty"`
ToSelectorMatchFields []SelectorMatchField `json:"dangerousToNamespacesSelector,omitempty"`
}

type SecretExportStatus struct {
Expand Down
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
73 changes: 53 additions & 20 deletions pkg/sharing/secret_exports.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package sharing

import (
"bytes"
"context"
"encoding/json"
"fmt"
Expand All @@ -12,10 +13,11 @@ import (
"sync"

"github.com/go-logr/logr"
"github.com/tidwall/gjson"
sg2v1alpha1 "github.com/vmware-tanzu/carvel-secretgen-controller/pkg/apis/secretgen2/v1alpha1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/jsonpath"
"sigs.k8s.io/controller-runtime/pkg/client"
)

const (
Expand All @@ -42,17 +44,23 @@ type SecretExportsProvider interface {
// (SecretExports is used by SecretExportReconciler to export/unexport secrets;
// SecretExports is used by SecretReconciler to determine imported secrets.)
type SecretExports struct {
log logr.Logger
log logr.Logger
k8sReader K8sReader

exportedSecretsLock sync.RWMutex
exportedSecrets map[string]exportedSecret
}

// K8sReader is an interface for reading Kubernetes resources.
type K8sReader interface {
Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error
}

var _ SecretExportsProvider = &SecretExports{}

// NewSecretExports constructs new SecretExports cache.
func NewSecretExports(log logr.Logger) *SecretExports {
return &SecretExports{log: log, exportedSecrets: map[string]exportedSecret{}}
func NewSecretExports(k8sReader K8sReader, log logr.Logger) *SecretExports {
return &SecretExports{log: log, k8sReader: k8sReader, exportedSecrets: map[string]exportedSecret{}}
}

// Export adds the in-memory representation (cached)
Expand Down Expand Up @@ -90,10 +98,15 @@ type SecretMatcher struct {
Subject string
SecretType corev1.SecretType

SecretImportReconciler *SecretImportReconciler
Ctx context.Context
Ctx context.Context
}

// DJO add this instead of selectors := es.export.Spec.ToSelectorMatchFields
// NamespacesMatcher allows to specify criteria for matching exported secrets based on namespaces fields.
// type NamespacesMatcher{

// }

// MatchedSecretsForImport filters secrets export cache by the given criteria.
// Returned order (last in the array is most specific):
// - secret with highest weight? (default weight=0), or
Expand All @@ -111,7 +124,7 @@ func (se *SecretExports) MatchedSecretsForImport(matcher SecretMatcher, nsIsExcl
var matched []exportedSecret

for _, exportedSec := range se.exportedSecrets {
if exportedSec.Matches(matcher, nsIsExcludedFromWildcard, se.log) {
if exportedSec.Matches(matcher, nsIsExcludedFromWildcard, se.log, se.k8sReader) {
matched = append(matched, exportedSec)
}
}
Expand Down Expand Up @@ -162,7 +175,7 @@ func (es exportedSecret) Secret() *corev1.Secret {
return es.secret.DeepCopy()
}

func (es exportedSecret) Matches(matcher SecretMatcher, nsIsExcludedFromWildcard NamespaceWildcardExclusionCheck, log logr.Logger) bool {
func (es exportedSecret) Matches(matcher SecretMatcher, nsIsExcludedFromWildcard NamespaceWildcardExclusionCheck, log logr.Logger, k8sReader K8sReader) bool {

if matcher.Subject != "" {
// TODO we currently do not match by subject
Expand All @@ -188,19 +201,43 @@ func (es exportedSecret) Matches(matcher SecretMatcher, nsIsExcludedFromWildcard
}

selectors := es.export.Spec.ToSelectorMatchFields
if len(selectors) > 0 {

isMatched := false

if es.matchesNamespace(matcher.ToNamespace, nsIsExcludedFromWildcard) {
isMatched = true
}

if !isMatched && len(selectors) > 0 {
nsName := matcher.ToNamespace
query := types.NamespacedName{
Name: nsName,
}
namespace := corev1.Namespace{}
err := matcher.SecretImportReconciler.client.Get(matcher.Ctx, query, &namespace)
err := k8sReader.Get(matcher.Ctx, query, &namespace)

jsonNsString, _ := json.Marshal(namespace)
var jsonNsObject interface{}
json.Unmarshal(jsonNsString, &jsonNsObject)

if err == nil {
jsonNs, _ := json.Marshal(namespace)

for _, s := range selectors {

jp := jsonpath.New("jsonpath")

jsonPathKey := "{." + s.Key + "}"
err := jp.Parse(jsonPathKey)
if err != nil {
log.Error(err, fmt.Sprintf("invalid jsonpath: %s", jsonPathKey))
return false
}
var valueBuffer bytes.Buffer
err = jp.Execute(&valueBuffer, jsonNsObject)
value := valueBuffer.String()

switch s.Operator {
case sg2v1alpha1.SelectorOperatorIn:
value := gjson.GetBytes(jsonNs, s.Key).String()
found := false
for _, svalue := range s.Values {
if svalue == value {
Expand All @@ -212,30 +249,26 @@ func (es exportedSecret) Matches(matcher SecretMatcher, nsIsExcludedFromWildcard
return false
}
case sg2v1alpha1.SelectorOperatorNotIn:
value := gjson.GetBytes(jsonNs, s.Key).String()
for _, svalue := range s.Values {
if svalue == value {
return false
}
}
case sg2v1alpha1.SelectorOperatorExists:
if !gjson.GetBytes(jsonNs, s.Key).Exists() {
if value != "" {
return false
}
case sg2v1alpha1.SelectorOperatorDoesNotExist:
if gjson.GetBytes(jsonNs, s.Key).Exists() {
if value != "" {
return false
}
}
}
return true
isMatched = true
}
}

if !es.matchesNamespace(matcher.ToNamespace, nsIsExcludedFromWildcard) {
return false
}
return true
return isMatched
}

func (es exportedSecret) matchesNamespace(nsToMatch string, nsIsExcludedFromWildcard NamespaceWildcardExclusionCheck) bool {
Expand Down
Loading

0 comments on commit e849c32

Please sign in to comment.