1 /* 2 Copyright 2024 The Flux authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package v1 18 19 import ( 20 "time" 21 22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 24 "github.com/fluxcd/pkg/apis/meta" 25 ) 26 27 const ( 28 // BucketKind is the string representation of a Bucket. 29 BucketKind = "Bucket" 30 ) 31 32 const ( 33 // BucketProviderGeneric for any S3 API compatible storage Bucket. 34 BucketProviderGeneric string = "generic" 35 // BucketProviderAmazon for an AWS S3 object storage Bucket. 36 // Provides support for retrieving credentials from the AWS EC2 service. 37 BucketProviderAmazon string = "aws" 38 // BucketProviderGoogle for a Google Cloud Storage Bucket. 39 // Provides support for authentication using a workload identity. 40 BucketProviderGoogle string = "gcp" 41 // BucketProviderAzure for an Azure Blob Storage Bucket. 42 // Provides support for authentication using a Service Principal, 43 // Managed Identity or Shared Key. 44 BucketProviderAzure string = "azure" 45 ) 46 47 // BucketSpec specifies the required configuration to produce an Artifact for 48 // an object storage bucket. 49 // +kubebuilder:validation:XValidation:rule="self.provider == 'aws' || self.provider == 'generic' || !has(self.sts)", message="STS configuration is only supported for the 'aws' and 'generic' Bucket providers" 50 // +kubebuilder:validation:XValidation:rule="self.provider != 'aws' || !has(self.sts) || self.sts.provider == 'aws'", message="'aws' is the only supported STS provider for the 'aws' Bucket provider" 51 // +kubebuilder:validation:XValidation:rule="self.provider != 'generic' || !has(self.sts) || self.sts.provider == 'ldap'", message="'ldap' is the only supported STS provider for the 'generic' Bucket provider" 52 // +kubebuilder:validation:XValidation:rule="!has(self.sts) || self.sts.provider != 'aws' || !has(self.sts.secretRef)", message="spec.sts.secretRef is not required for the 'aws' STS provider" 53 // +kubebuilder:validation:XValidation:rule="!has(self.sts) || self.sts.provider != 'aws' || !has(self.sts.certSecretRef)", message="spec.sts.certSecretRef is not required for the 'aws' STS provider" 54 type BucketSpec struct { 55 // Provider of the object storage bucket. 56 // Defaults to 'generic', which expects an S3 (API) compatible object 57 // storage. 58 // +kubebuilder:validation:Enum=generic;aws;gcp;azure 59 // +kubebuilder:default:=generic 60 // +optional 61 Provider string `json:"provider,omitempty"` 62 63 // BucketName is the name of the object storage bucket. 64 // +required 65 BucketName string `json:"bucketName"` 66 67 // Endpoint is the object storage address the BucketName is located at. 68 // +required 69 Endpoint string `json:"endpoint"` 70 71 // STS specifies the required configuration to use a Security Token 72 // Service for fetching temporary credentials to authenticate in a 73 // Bucket provider. 74 // 75 // This field is only supported for the `aws` and `generic` providers. 76 // +optional 77 STS *BucketSTSSpec `json:"sts,omitempty"` 78 79 // Insecure allows connecting to a non-TLS HTTP Endpoint. 80 // +optional 81 Insecure bool `json:"insecure,omitempty"` 82 83 // Region of the Endpoint where the BucketName is located in. 84 // +optional 85 Region string `json:"region,omitempty"` 86 87 // Prefix to use for server-side filtering of files in the Bucket. 88 // +optional 89 Prefix string `json:"prefix,omitempty"` 90 91 // SecretRef specifies the Secret containing authentication credentials 92 // for the Bucket. 93 // +optional 94 SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"` 95 96 // CertSecretRef can be given the name of a Secret containing 97 // either or both of 98 // 99 // - a PEM-encoded client certificate (`tls.crt`) and private 100 // key (`tls.key`); 101 // - a PEM-encoded CA certificate (`ca.crt`) 102 // 103 // and whichever are supplied, will be used for connecting to the 104 // bucket. The client cert and key are useful if you are 105 // authenticating with a certificate; the CA cert is useful if 106 // you are using a self-signed server certificate. The Secret must 107 // be of type `Opaque` or `kubernetes.io/tls`. 108 // 109 // This field is only supported for the `generic` provider. 110 // +optional 111 CertSecretRef *meta.LocalObjectReference `json:"certSecretRef,omitempty"` 112 113 // ProxySecretRef specifies the Secret containing the proxy configuration 114 // to use while communicating with the Bucket server. 115 // +optional 116 ProxySecretRef *meta.LocalObjectReference `json:"proxySecretRef,omitempty"` 117 118 // Interval at which the Bucket Endpoint is checked for updates. 119 // This interval is approximate and may be subject to jitter to ensure 120 // efficient use of resources. 121 // +kubebuilder:validation:Type=string 122 // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" 123 // +required 124 Interval metav1.Duration `json:"interval"` 125 126 // Timeout for fetch operations, defaults to 60s. 127 // +kubebuilder:default="60s" 128 // +kubebuilder:validation:Type=string 129 // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m))+$" 130 // +optional 131 Timeout *metav1.Duration `json:"timeout,omitempty"` 132 133 // Ignore overrides the set of excluded patterns in the .sourceignore format 134 // (which is the same as .gitignore). If not provided, a default will be used, 135 // consult the documentation for your version to find out what those are. 136 // +optional 137 Ignore *string `json:"ignore,omitempty"` 138 139 // Suspend tells the controller to suspend the reconciliation of this 140 // Bucket. 141 // +optional 142 Suspend bool `json:"suspend,omitempty"` 143 } 144 145 // BucketSTSSpec specifies the required configuration to use a Security Token 146 // Service for fetching temporary credentials to authenticate in a Bucket 147 // provider. 148 type BucketSTSSpec struct { 149 // Provider of the Security Token Service. 150 // +kubebuilder:validation:Enum=aws;ldap 151 // +required 152 Provider string `json:"provider"` 153 154 // Endpoint is the HTTP/S endpoint of the Security Token Service from 155 // where temporary credentials will be fetched. 156 // +required 157 // +kubebuilder:validation:Pattern="^(http|https)://.*$" 158 Endpoint string `json:"endpoint"` 159 160 // SecretRef specifies the Secret containing authentication credentials 161 // for the STS endpoint. This Secret must contain the fields `username` 162 // and `password` and is supported only for the `ldap` provider. 163 // +optional 164 SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"` 165 166 // CertSecretRef can be given the name of a Secret containing 167 // either or both of 168 // 169 // - a PEM-encoded client certificate (`tls.crt`) and private 170 // key (`tls.key`); 171 // - a PEM-encoded CA certificate (`ca.crt`) 172 // 173 // and whichever are supplied, will be used for connecting to the 174 // STS endpoint. The client cert and key are useful if you are 175 // authenticating with a certificate; the CA cert is useful if 176 // you are using a self-signed server certificate. The Secret must 177 // be of type `Opaque` or `kubernetes.io/tls`. 178 // 179 // This field is only supported for the `ldap` provider. 180 // +optional 181 CertSecretRef *meta.LocalObjectReference `json:"certSecretRef,omitempty"` 182 } 183 184 // BucketStatus records the observed state of a Bucket. 185 type BucketStatus struct { 186 // ObservedGeneration is the last observed generation of the Bucket object. 187 // +optional 188 ObservedGeneration int64 `json:"observedGeneration,omitempty"` 189 190 // Conditions holds the conditions for the Bucket. 191 // +optional 192 Conditions []metav1.Condition `json:"conditions,omitempty"` 193 194 // URL is the dynamic fetch link for the latest Artifact. 195 // It is provided on a "best effort" basis, and using the precise 196 // BucketStatus.Artifact data is recommended. 197 // +optional 198 URL string `json:"url,omitempty"` 199 200 // Artifact represents the last successful Bucket reconciliation. 201 // +optional 202 Artifact *Artifact `json:"artifact,omitempty"` 203 204 // ObservedIgnore is the observed exclusion patterns used for constructing 205 // the source artifact. 206 // +optional 207 ObservedIgnore *string `json:"observedIgnore,omitempty"` 208 209 meta.ReconcileRequestStatus `json:",inline"` 210 } 211 212 const ( 213 // BucketOperationSucceededReason signals that the Bucket listing and fetch 214 // operations succeeded. 215 BucketOperationSucceededReason string = "BucketOperationSucceeded" 216 217 // BucketOperationFailedReason signals that the Bucket listing or fetch 218 // operations failed. 219 BucketOperationFailedReason string = "BucketOperationFailed" 220 ) 221 222 // GetConditions returns the status conditions of the object. 223 func (in *Bucket) GetConditions() []metav1.Condition { 224 return in.Status.Conditions 225 } 226 227 // SetConditions sets the status conditions on the object. 228 func (in *Bucket) SetConditions(conditions []metav1.Condition) { 229 in.Status.Conditions = conditions 230 } 231 232 // GetRequeueAfter returns the duration after which the source must be reconciled again. 233 func (in *Bucket) GetRequeueAfter() time.Duration { 234 return in.Spec.Interval.Duration 235 } 236 237 // GetArtifact returns the latest artifact from the source if present in the status sub-resource. 238 func (in *Bucket) GetArtifact() *Artifact { 239 return in.Status.Artifact 240 } 241 242 // +genclient 243 // +kubebuilder:storageversion 244 // +kubebuilder:object:root=true 245 // +kubebuilder:subresource:status 246 // +kubebuilder:printcolumn:name="Endpoint",type=string,JSONPath=`.spec.endpoint` 247 // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" 248 // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="" 249 // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description="" 250 251 // Bucket is the Schema for the buckets API. 252 type Bucket struct { 253 metav1.TypeMeta `json:",inline"` 254 metav1.ObjectMeta `json:"metadata,omitempty"` 255 256 Spec BucketSpec `json:"spec,omitempty"` 257 // +kubebuilder:default={"observedGeneration":-1} 258 Status BucketStatus `json:"status,omitempty"` 259 } 260 261 // BucketList contains a list of Bucket objects. 262 // +kubebuilder:object:root=true 263 type BucketList struct { 264 metav1.TypeMeta `json:",inline"` 265 metav1.ListMeta `json:"metadata,omitempty"` 266 Items []Bucket `json:"items"` 267 } 268 269 func init() { 270 SchemeBuilder.Register(&Bucket{}, &BucketList{}) 271 } 272