-
Notifications
You must be signed in to change notification settings - Fork 30
/
spiaccesstokenbinding_types.go
253 lines (215 loc) · 12.2 KB
/
spiaccesstokenbinding_types.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
Copyright 2021.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1
import (
"fmt"
"reflect"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// SPIAccessTokenBindingSpec defines the desired state of SPIAccessTokenBinding
type SPIAccessTokenBindingSpec struct {
// RepoUrl is just the URL of the repository for which the access token is requested.
RepoUrl string `json:"repoUrl"`
// Permissions is the set of permissions that the creator of the binding requires
// the access token to allow in the target repository.
Permissions Permissions `json:"permissions,omitempty"`
// Secret is the specification of the secret that should contain the access token.
// The secret will be created in the same namespace as this binding object.
Secret SecretSpec `json:"secret"`
// Lifetime specifies how long the binding and its associated data should live.
// This is specified as time with a unit (30m, 2h). A special value of "-1" means
// infinite lifetime.
Lifetime string `json:"lifetime,omitempty"`
}
type ServiceAccountLinkType string
const (
ServiceAccountLinkTypeSecret ServiceAccountLinkType = "secret"
ServiceAccountLinkTypeImagePullSecret ServiceAccountLinkType = "imagePullSecret"
)
// SPIAccessTokenBindingStatus defines the observed state of SPIAccessTokenBinding
type SPIAccessTokenBindingStatus struct {
Phase SPIAccessTokenBindingPhase `json:"phase"`
ErrorReason SPIAccessTokenBindingErrorReason `json:"errorReason,omitempty"`
ErrorMessage string `json:"errorMessage,omitempty"`
LinkedAccessTokenName string `json:"linkedAccessTokenName"`
OAuthUrl string `json:"oAuthUrl,omitempty"`
UploadUrl string `json:"uploadUrl,omitempty"`
SyncedObjectRef TargetObjectRef `json:"syncedObjectRef"`
ServiceAccountNames []string `json:"serviceAccountNames,omitempty"`
}
type SPIAccessTokenBindingPhase string
const (
SPIAccessTokenBindingPhaseAwaitingTokenData SPIAccessTokenBindingPhase = "AwaitingTokenData"
SPIAccessTokenBindingPhaseInjected SPIAccessTokenBindingPhase = "Injected"
SPIAccessTokenBindingPhaseError SPIAccessTokenBindingPhase = "Error"
)
type SPIAccessTokenBindingErrorReason string
const (
SPIAccessTokenBindingErrorReasonUnknownServiceProviderType SPIAccessTokenBindingErrorReason = "UnknownServiceProviderType"
SPIAccessTokenBindingErrorUnsupportedServiceProviderConfiguration SPIAccessTokenBindingErrorReason = "UnsupportedServiceProviderConfiguration"
SPIAccessTokenBindingErrorReasonInvalidLifetime SPIAccessTokenBindingErrorReason = "InvalidLifetime"
SPIAccessTokenBindingErrorReasonTokenLookup SPIAccessTokenBindingErrorReason = "TokenLookup"
SPIAccessTokenBindingErrorReasonLinkedToken SPIAccessTokenBindingErrorReason = "LinkedToken"
SPIAccessTokenBindingErrorReasonTokenRetrieval SPIAccessTokenBindingErrorReason = "TokenRetrieval"
SPIAccessTokenBindingErrorReasonTokenSync SPIAccessTokenBindingErrorReason = "TokenSync"
SPIAccessTokenBindingErrorReasonTokenAnalysis SPIAccessTokenBindingErrorReason = "TokenAnalysis"
SPIAccessTokenBindingErrorReasonUnsupportedPermissions SPIAccessTokenBindingErrorReason = "UnsupportedPermissions"
SPIAccessTokenBindingErrorReasonInconsistentSpec SPIAccessTokenBindingErrorReason = "InconsistentSpec"
SPIAccessTokenBindingErrorReasonServiceAccountUnavailable SPIAccessTokenBindingErrorReason = "ServiceAccountUnavailable"
SPIAccessTokenBindingErrorReasonServiceAccountUpdate SPIAccessTokenBindingErrorReason = "ServiceAccountUpdate"
SPIAccessTokenBindingErrorReasonNoError SPIAccessTokenBindingErrorReason = ""
)
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// SPIAccessTokenBinding is the Schema for the spiaccesstokenbindings API
type SPIAccessTokenBinding struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec SPIAccessTokenBindingSpec `json:"spec,omitempty"`
Status SPIAccessTokenBindingStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// SPIAccessTokenBindingList contains a list of SPIAccessTokenBinding
type SPIAccessTokenBindingList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []SPIAccessTokenBinding `json:"items"`
}
type LinkableSecretSpec struct {
// Name is the name of the secret to be created. If it is not defined a random name based on the name of the binding
// is used.
// +optional
Name string `json:"name,omitempty"`
GenerateName string `json:"generateName,omitempty"`
// Labels contains the labels that the created secret should be labeled with.
Labels map[string]string `json:"labels,omitempty"`
// Annotations is the keys and values that the create secret should be annotated with.
Annotations map[string]string `json:"annotations,omitempty"`
// Type is the type of the secret to be created. If left empty, the default type used in the cluster is assumed (typically Opaque).
// The type of the secret defines the automatic mapping of the token record fields to keys in the secret data
// according to the documentation https://kubernetes.io/docs/concepts/configuration/secret/#secret-types.
// Only kubernetes.io/service-account-token, kubernetes.io/dockercfg, kubernetes.io/dockerconfigjson and kubernetes.io/basic-auth
// are supported. All other secret types need to have their mapping specified manually using the Fields.
Type corev1.SecretType `json:"type,omitempty"`
// LinkedTo specifies the objects that the secret is linked to. Currently, only service accounts are supported.
LinkedTo []SecretLink `json:"linkedTo,omitempty"`
}
type SecretSpec struct {
LinkableSecretSpec `json:",inline"`
// Fields specifies the mapping from the token record fields to the keys in the secret data.
Fields TokenFieldMapping `json:"fields,omitempty"`
}
type TokenFieldMapping struct {
// Token specifies the data key in which the token should be stored.
Token string `json:"token,omitempty"`
// Name specifies the data key in which the name of the token record should be stored.
Name string `json:"name,omitempty"`
// ServiceProviderUrl specifies the data key in which the url of the service provider should be stored.
ServiceProviderUrl string `json:"serviceProviderUrl,omitempty"`
// ServiceProviderUserName specifies the data key in which the url of the user name used in the service provider should be stored.
ServiceProviderUserName string `json:"serviceProviderUserName,omitempty"`
// ServiceProviderUserId specifies the data key in which the url of the user id used in the service provider should be stored.
ServiceProviderUserId string `json:"serviceProviderUserId,omitempty"`
// UserId specifies the data key in which the user id as known to the SPI should be stored (note that this is usually different from
// ServiceProviderUserId, because the former is usually a kubernetes user, while the latter is some arbitrary ID used by the service provider
// which might or might not correspond to the Kubernetes user id).
UserId string `json:"userId,omitempty"`
// ExpiredAfter specifies the data key in which the expiry date of the token should be stored.
ExpiredAfter string `json:"expiredAfter,omitempty"`
// Scopes specifies the data key in which the comma-separated list of token scopes should be stored.
Scopes string `json:"scopes,omitempty"`
}
type SecretLink struct {
// ServiceAccounts lists the service accounts that the secret is linked to.
ServiceAccount ServiceAccountLink `json:"serviceAccount,omitempty"`
}
type ServiceAccountLink struct {
// As specifies how the secret generated by the binding is linked to the service account.
// This can be either `secret` meaning that the secret is listed as one of the mountable secrets
// in the `secrets` of the service account, `imagePullSecret` which makes the secret listed as
// one of the image pull secrets associated with the service account. If not specified, it defaults
// to `secret`.
// +optional
// +kubebuilder:default:=secret
As ServiceAccountLinkType `json:"as,omitempty"`
// Reference specifies a pre-existing service account that the secret should be linked to. It is an error
// if the service account doesn't exist when the operator tries to add a link to a secret with the injected
// token.
Reference corev1.LocalObjectReference `json:"reference,omitempty"`
// Managed specifies the service account that is bound to the lifetime of the binding. This service account
// must not exist and is created and deleted along with the injected secret.
Managed ManagedServiceAccountSpec `json:"managed,omitempty"`
}
type ManagedServiceAccountSpec struct {
// Name is the name of the service account to create/link. Either this or GenerateName
// must be specified.
// +optional
Name string `json:"name"`
// GenerateName is the generate name to be used when creating the service account. It only
// really makes sense for the Managed service accounts that are cleaned up with the binding.
// +optional
GenerateName string `json:"generateName"`
// Labels contains the labels that the created service account should be labeled with.
Labels map[string]string `json:"labels,omitempty"`
// Annotations is the keys and values that the created service account should be annotated with.
Annotations map[string]string `json:"annotations,omitempty"`
}
type TargetObjectRef struct {
// Name is the name of the object with the injected data. This always lives in the same namespace as the AccessTokenSecret object.
Name string `json:"name"`
// Kind is the kind of the object with the injected data.
Kind string `json:"kind"`
// ApiVersion is the api version of the object with the injected data.
ApiVersion string `json:"apiVersion"`
}
type SPIAccessTokenBindingValidation struct {
// Consistency is the list of consistency validation errors
Consistency []string
}
func init() {
SchemeBuilder.Register(&SPIAccessTokenBinding{}, &SPIAccessTokenBindingList{})
}
func (in *SPIAccessTokenBinding) RepoUrl() string {
return in.Spec.RepoUrl
}
func (in *SPIAccessTokenBinding) ObjNamespace() string {
return in.Namespace
}
func (in *SPIAccessTokenBinding) Permissions() *Permissions {
return &in.Spec.Permissions
}
func (in *SPIAccessTokenBinding) Validate() SPIAccessTokenBindingValidation {
ret := SPIAccessTokenBindingValidation{}
for i, link := range in.Spec.Secret.LinkedTo {
if link.ServiceAccount.Reference.Name != "" && (link.ServiceAccount.Managed.Name != "" || link.ServiceAccount.Managed.GenerateName != "") {
ret.Consistency = append(ret.Consistency, fmt.Sprintf("The %d-th service account spec defines both a service account reference and the managed service account. This is invalid", i+1))
}
if in.Spec.Secret.Type != corev1.SecretTypeDockerConfigJson && link.ServiceAccount.As == ServiceAccountLinkTypeImagePullSecret {
ret.Consistency = append(ret.Consistency,
fmt.Sprintf("the secret must have the %s type for it to be linkable to the %d-th service account spec as an image pull secret", corev1.SecretTypeDockerConfigJson, i+1))
}
}
return ret
}
func (mapping *TokenFieldMapping) Empty() bool {
return reflect.DeepEqual(mapping, &TokenFieldMapping{})
}
// EffectiveSecretLinkType returns the secret link type applying the default value if LinkedSecretAs is unspecified by
// the user.
func (s *ServiceAccountLink) EffectiveSecretLinkType() ServiceAccountLinkType {
if s.As == ServiceAccountLinkTypeImagePullSecret {
return ServiceAccountLinkTypeImagePullSecret
}
return ServiceAccountLinkTypeSecret
}