/
secrets.go
121 lines (97 loc) · 3.68 KB
/
secrets.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT license.
*/
package genruntime
import (
"fmt"
"github.com/Azure/azure-service-operator/v2/internal/set"
"github.com/pkg/errors"
)
// SecretReference is a reference to a Kubernetes secret and key in the same namespace as
// the resource it is on.
// +kubebuilder:object:generate=true
type SecretReference struct {
// SecretName is the name of the Kubernetes secret being referenced.
// The secret must be in the same namespace as the resource
// +kubebuilder:validation:Required
Name string `json:"name"`
// Key is the key in the Kubernetes secret being referenced
// +kubebuilder:validation:Required
Key string `json:"key"`
// If we end up wanting to support secrets from KeyVault (or elsewhere) we should be able to add a
// Type *SecretType
// here and default it to Kubernetes if it's not set. See the secrets design for more details.
}
// Copy makes an independent copy of the SecretReference
func (s SecretReference) Copy() SecretReference {
return s
}
func (s SecretReference) String() string {
return fmt.Sprintf("Name: %q, Key: %q", s.Name, s.Key)
}
// ToNamespacedRef creates a NamespacedSecretReference from this SecretReference in the given namespace
func (s SecretReference) ToNamespacedRef(namespace string) NamespacedSecretReference {
return NamespacedSecretReference{
SecretReference: s,
Namespace: namespace,
}
}
// NamespacedSecretReference is a SecretReference with namespace information included
type NamespacedSecretReference struct {
SecretReference
Namespace string
}
func (s NamespacedSecretReference) String() string {
return fmt.Sprintf("Namespace: %q, %s", s.Namespace, s.SecretReference.String())
}
// SecretDestination describes the location to store a single secret value
type SecretDestination struct {
// Note: We could embed SecretReference here, but it makes our life harder because then our reflection based tools will "find" SecretReference's
// inside of SecretDestination and try to resolve them. It also gives a worse experience when using the Go Types (the YAML is the same either way).
// SecretName is the name of the Kubernetes secret being referenced.
// The secret must be in the same namespace as the resource
// +kubebuilder:validation:Required
Name string `json:"name"`
// Key is the key in the Kubernetes secret being referenced
// +kubebuilder:validation:Required
Key string `json:"key"`
// This is a type separate from SecretReference as in the future we may want to support things like
// customizable annotations or labels, instructions to not delete the secret when the resource is
// deleted, etc. None of those things make sense for SecretReference so using the exact same type isn't
// advisable.
}
// Copy makes an independent copy of the SecretDestination
func (s SecretDestination) Copy() SecretDestination {
return s
}
func (s SecretDestination) String() string {
return fmt.Sprintf("Name: %q, Key: %q", s.Name, s.Key)
}
type secretKeyPair struct {
secret string
key string
}
func makeKeyPair(dest *SecretDestination) secretKeyPair {
return secretKeyPair{
secret: dest.Name,
key: dest.Key,
}
}
// ValidateSecretDestinations checks that no destination is writing to the same secret/key, as that could cause
// those secrets to overwrite one another.
func ValidateSecretDestinations(destinations []*SecretDestination) error {
// Map of secret -> keys
locations := set.Make[secretKeyPair]()
for _, dest := range destinations {
if dest == nil {
continue
}
pair := makeKeyPair(dest)
if locations.Contains(pair) {
return errors.Errorf("cannot write more than one secret to destination %s", dest.String())
}
locations.Add(pair)
}
return nil
}