Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,24 @@ kubectl apply -f example/deploy/gcore-sfs-controller-install.yaml
### Install CRD
1. You must fill in the next values:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: gcore-api-token
namespace: gcore-sfs-controller-system
stringData:
apiToken: <put your api token here>
---
spec:
apiToken: <put your api token here>
region: <put your region id here>
project: <put your project id here>
apiTokenSecretRef:
name: gcore-api-token
key: apiToken
region: <put your region id here>
project: <put your project id here>
```
`apiToken`: Create API token in [CLOUD UI](https://gcore.com/docs/account-settings/create-use-or-delete-a-permanent-api-token).
`apiTokenSecretRef`: References a key of a Secret (in the same namespace as the NfsProvisioner) holding your API token. Create API token in [CLOUD UI](https://gcore.com/docs/account-settings/create-use-or-delete-a-permanent-api-token).

**Note:** The `spec.apiToken` field (plaintext token stored directly in the custom resource) is deprecated because anyone able to read the resource can read the token. Use `apiTokenSecretRef` instead.


`region`: You can get a region id from our [API](https://api.gcore.com/docs/cloud#tag/Regions/operation/RegionHandler.get): You will get a list of regions from the "v1/regions" handler, and then you can find the needed region by the "display_name" field.
Expand Down
19 changes: 18 additions & 1 deletion api/v1/nfsprovisioner_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,34 @@ limitations under the License.
package v1

import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// NfsProvisionerFinalizer is the finalizer applied to NfsProvisioner resources
// by its managing controller.
const NfsProvisionerFinalizer = "nfsprovisioner.gcore-sfs-controller.io"

// DefaultAPITokenSecretKey is the Secret key used when
// spec.apiTokenSecretRef does not specify one.
const DefaultAPITokenSecretKey = "apiToken"

// NfsProvisionerSpec defines the desired state of NfsProvisioner
type NfsProvisionerSpec struct {
// APIToken is the API token used to authenticate with Gcore Cloud.
APIToken string `json:"apiToken"`
//
// Deprecated: storing the token in the custom resource exposes it to
// anyone who can read the resource (kubectl get, etcd backups, audit
// logs). Use APITokenSecretRef instead.
// +optional
APIToken string `json:"apiToken,omitempty"`

// APITokenSecretRef references a key of a Secret in the same namespace
// as the NfsProvisioner that holds the Gcore Cloud API token.
// If the key is not specified, it defaults to "apiToken".
// Exactly one of APIToken and APITokenSecretRef must be set.
// +optional
APITokenSecretRef *corev1.SecretKeySelector `json:"apiTokenSecretRef,omitempty"`
// APIURL is the URL of the Gcore Cloud API.
// +optional
APIURL string `json:"apiURL,omitempty"`
Expand Down
16 changes: 15 additions & 1 deletion api/v1/nfsprovisioner_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ func (r *NfsProvisioner) Default() {
r.Spec.ImageVersion = DefaultNfsProvisionerImageVersion
}
nfsprovisionerlog.Info("default", "imageVersion", r.Spec.ImageVersion)
if r.Spec.APITokenSecretRef != nil && r.Spec.APITokenSecretRef.Key == "" {
r.Spec.APITokenSecretRef.Key = DefaultAPITokenSecretKey
}
}

//+kubebuilder:webhook:path=/validate-crd-gcore-sfs-controller-io-v1-nfsprovisioner,mutating=false,failurePolicy=fail,sideEffects=None,groups=crd.gcore-sfs-controller.io,resources=nfsprovisioners,verbs=create;update,versions=v1,name=vnfsprovisioner.kb.io,admissionReviewVersions=v1
Expand All @@ -79,9 +82,20 @@ func ValidateNfsProvisioner(r *NfsProvisioner) error {
allErrs = append(allErrs, regionErr)
}
if r.Spec.ProjectID <= 0 {
projectErr := field.Invalid(field.NewPath("spec").Child("project"), r.Spec.RegionID, "must be positive")
projectErr := field.Invalid(field.NewPath("spec").Child("project"), r.Spec.ProjectID, "must be positive")
allErrs = append(allErrs, projectErr)
}
switch {
case r.Spec.APIToken == "" && r.Spec.APITokenSecretRef == nil:
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("apiTokenSecretRef"),
"one of apiToken or apiTokenSecretRef must be set"))
case r.Spec.APIToken != "" && r.Spec.APITokenSecretRef != nil:
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec").Child("apiToken"),
"apiToken and apiTokenSecretRef are mutually exclusive"))
case r.Spec.APITokenSecretRef != nil && r.Spec.APITokenSecretRef.Name == "":
allErrs = append(allErrs, field.Required(field.NewPath("spec").Child("apiTokenSecretRef").Child("name"),
"secret name must be set"))
}
Comment on lines +88 to +98
if len(allErrs) == 0 {
return nil
}
Expand Down
64 changes: 64 additions & 0 deletions api/v1/nfsprovisioner_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down Expand Up @@ -59,6 +60,9 @@ var _ = Describe("NfsProvisioner webhooks", func() {
Namespace: "default",
},
Spec: NfsProvisionerSpec{
APITokenSecretRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{Name: "gcore-api-token"},
},
RegionID: 1,
ProjectID: 1,
},
Expand All @@ -69,5 +73,65 @@ var _ = Describe("NfsProvisioner webhooks", func() {
Expect(provisioner.Spec.HelmRepository).To(Equal(DefaultHelmRepository))
Expect(provisioner.Spec.ChartName).To(Equal(DefaultHelmChartName))
Expect(provisioner.Spec.ImageVersion).To(Equal(DefaultNfsProvisionerImageVersion))
Expect(provisioner.Spec.APITokenSecretRef.Key).To(Equal(DefaultAPITokenSecretKey))
})
It("Check NfsProvisioner webhook rejects missing API token configuration", func() {
provisioner := NfsProvisioner{
TypeMeta: metav1.TypeMeta{
Kind: "NfsProvisioner",
APIVersion: GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "provisioner-no-token",
Namespace: "default",
},
Spec: NfsProvisionerSpec{
RegionID: 1,
ProjectID: 1,
},
}
err := k8sClient.Create(ctx, &provisioner)
Expect(err).To(MatchError(ContainSubstring("one of apiToken or apiTokenSecretRef must be set")))
})
It("Check NfsProvisioner webhook rejects both apiToken and apiTokenSecretRef", func() {
provisioner := NfsProvisioner{
TypeMeta: metav1.TypeMeta{
Kind: "NfsProvisioner",
APIVersion: GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "provisioner-both-tokens",
Namespace: "default",
},
Spec: NfsProvisionerSpec{
APIToken: "faketoken",
APITokenSecretRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{Name: "gcore-api-token"},
},
RegionID: 1,
ProjectID: 1,
},
}
err := k8sClient.Create(ctx, &provisioner)
Expect(err).To(MatchError(ContainSubstring("mutually exclusive")))
})
It("Check NfsProvisioner webhook rejects apiTokenSecretRef without a name", func() {
provisioner := NfsProvisioner{
TypeMeta: metav1.TypeMeta{
Kind: "NfsProvisioner",
APIVersion: GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "provisioner-unnamed-secret",
Namespace: "default",
},
Spec: NfsProvisionerSpec{
APITokenSecretRef: &corev1.SecretKeySelector{},
RegionID: 1,
ProjectID: 1,
},
}
err := k8sClient.Create(ctx, &provisioner)
Expect(err).To(MatchError(ContainSubstring("secret name must be set")))
})
})
8 changes: 7 additions & 1 deletion api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 25 additions & 3 deletions config/crd/bases/crd.gcore-sfs-controller.io_nfsprovisioners.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,32 @@ spec:
description: NfsProvisionerSpec defines the desired state of NfsProvisioner
properties:
apiToken:
description: APIToken is the API token used to authenticate with Gcore
Cloud.
description: "APIToken is the API token used to authenticate with
Gcore Cloud. \n Deprecated: storing the token in the custom resource
exposes it to anyone who can read the resource (kubectl get, etcd
backups, audit logs). Use APITokenSecretRef instead."
type: string
apiTokenSecretRef:
description: APITokenSecretRef references a key of a Secret in the
same namespace as the NfsProvisioner that holds the Gcore Cloud
API token. If the key is not specified, it defaults to "apiToken".
Exactly one of APIToken and APITokenSecretRef must be set.
properties:
key:
description: The key of the secret to select from. Must be a
valid secret key.
type: string
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
optional:
description: Specify whether the Secret or its key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
apiURL:
description: APIURL is the URL of the Gcore Cloud API.
type: string
Expand All @@ -64,7 +87,6 @@ spec:
description: File share region ID
type: integer
required:
- apiToken
- project
- region
type: object
Expand Down
11 changes: 10 additions & 1 deletion config/samples/crd_v1_nfsprovisioner.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: gcore-api-token
stringData:
apiToken: <put your api token here>
---
apiVersion: crd.gcore-sfs-controller.io/v1
kind: NfsProvisioner
metadata:
Expand All @@ -9,6 +16,8 @@ metadata:
app.kubernetes.io/created-by: gcore-sfs-controller
name: nfsprovisioner-sample
spec:
apiToken: <put your api token here>
apiTokenSecretRef:
name: gcore-api-token
key: apiToken
region: <put your region id here>
project: <put your project id here>
28 changes: 25 additions & 3 deletions example/deploy/gcore-sfs-controller-install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,32 @@ spec:
description: NfsProvisionerSpec defines the desired state of NfsProvisioner
properties:
apiToken:
description: APIToken is the API token used to authenticate with Gcore
Cloud.
description: "APIToken is the API token used to authenticate with
Gcore Cloud. \n Deprecated: storing the token in the custom resource
exposes it to anyone who can read the resource (kubectl get, etcd
backups, audit logs). Use APITokenSecretRef instead."
type: string
apiTokenSecretRef:
description: APITokenSecretRef references a key of a Secret in the
same namespace as the NfsProvisioner that holds the Gcore Cloud
API token. If the key is not specified, it defaults to "apiToken".
Exactly one of APIToken and APITokenSecretRef must be set.
properties:
key:
description: The key of the secret to select from. Must be a
valid secret key.
type: string
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
optional:
description: Specify whether the Secret or its key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
apiURL:
description: APIURL is the URL of the Gcore Cloud API.
type: string
Expand All @@ -87,7 +110,6 @@ spec:
description: File share region ID
type: integer
required:
- apiToken
- project
- region
type: object
Expand Down
12 changes: 11 additions & 1 deletion example/deploy/nfsprovisioner.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: gcore-api-token
namespace: gcore-sfs-controller-system
stringData:
apiToken: <put your api token here>
---
apiVersion: crd.gcore-sfs-controller.io/v1
kind: NfsProvisioner
metadata:
Expand All @@ -10,6 +18,8 @@ metadata:
name: nfsprovisioner
namespace: gcore-sfs-controller-system
spec:
apiToken: <put your api token here>
apiTokenSecretRef:
name: gcore-api-token
key: apiToken
region: <put your region id here>
project: <put your project id here>
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
k8s.io/apimachinery v0.27.3
k8s.io/client-go v0.27.3
sigs.k8s.io/controller-runtime v0.15.0
sigs.k8s.io/yaml v1.3.0
)

require (
Expand Down Expand Up @@ -157,7 +158,6 @@ require (
sigs.k8s.io/kustomize/api v0.13.2 // indirect
sigs.k8s.io/kustomize/kyaml v0.14.1 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

replace github.com/G-Core/gcore-sfs-controller/pkg/gcoreclient => ./pkg/gcoreclient
Loading