Skip to content

Tutorials: storage-minio

These tutorials offer a series of steps to install, run and deploy your first Claim for the storage-minio configuration package. We are going to create buckets for Alice and Bob, two imaginary users. Then, Alice is going to request access to a bucket which is owned by Bob and in the last step Bob is going to grant access to Alice for this bucket.

Prerequisites

This tutorial assumes that you have go, kubectl and helm installed on your machine. Furthermore, we are using a local kind cluster for this tutorial. You can find installation instructions here.

kind cluster and crossplane installation

After you have installed the necessary tools, we can create a new cluster with

kind create cluster --name storage-minio

and check if everything is working with

kubectl get pods -A

If the cluster is up and running, we need to install Crossplane. You can find more information about the installation process here.

helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane \
--namespace crossplane-system \
--create-namespace crossplane-stable/crossplane \
--version 1.20.0

MinIO installation

In order to test the functionality of storage-minio we need a MinIO installation. For this tutorial we install MinIO into our cluster as well.

First, we need to install the minio-operator.

helm repo add minio-operator https://operator.min.io
helm install \
  --namespace minio-operator \
  --create-namespace \
  operator minio-operator/operator

Next, we need to install a minio-tenant. This is where our Buckets, Policies and Users actually live. Since this is only for testing, we will make the footprint of the tenant as small as possible by configuring the installation with a values.yaml file.

# values.yaml

tenant:
  pools:
    - servers: 1
      name: pool-0
      volumesPerServer: 1
      size: 1Gi
  certificate:
    requestAutoCert: false

Now we can install the minio-tenant with

helm install \
  --values values.yaml \
  --namespace minio-tenant \
  --create-namespace \
  minio-tenant minio-operator/tenant

This concludes the prerequisites and we can finally isntall the storage-minio configuration package.

storage-minio configuration package installation

In order to install the storage-minio configuration package, we first need to create a Configuration.

# configuration.yaml

apiVersion: pkg.crossplane.io/v1
kind: Configuration
metadata:
  name: storage-minio
spec:
  package: ghcr.io/versioneer-tech/provider-storage:v0.2-minio

Then, we need to apply it to the cluster with

kubectl apply -f configuration.yaml

This automatically installs the necessary dependencies specified in the configuration package:

You can check this by running

kubectl get pods -A

and confirm that you see pods name crossplane-contrib-function-auto-ready-..., crossplane-contrib-provider-kubernetes-..., etc. Furthermore, you should now see one CompositeResourceDefinition or XRD and one Composition with

kubectl get xrds
kubectl get compositions

The storage-minio configuration package is now installed. However, it is not functional yet since it does not install the necessary ProviderConfigs, ServiceAccounts, ClusterRoles, ClusterRoleBindings and Secrets that are needed by the provider-minio and provider-kubernetes.

provider-minio configuration

For storage-minio to work, we need to configure the providers with a ProviderConfig.

Let's start with provider-minio. In order for the provider to know where to actually create the resources specified in the Crossplane composition, we need to provide it with connection details through a ProviderConfig.

Since we are using the MinIO instance installed in the cluster, we can forward the port for the web interface and create an API key.

kubectl port-forward pod/myminio-pool-0-0 -n minio-tenant 9090 9090

Navigate to http://localhost:9090 and login with the username minio and minio123. Click on Access Keys and create a new access key.

Then we need to create a Secret with the new access keys for provider-minio to connect.

# secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: storage-minio
  namespace: minio-tenant
stringData:
  AWS_ACCESS_KEY_ID: <Access Key>
  AWS_SECRET_ACCESS_KEY: <Secret Key>
kubectl apply -f secret.yaml

Finally, we can finish the setup for provider-minio by applying a ProviderConfig that references this secret.

# minio-provider-config.yaml

apiVersion: minio.crossplane.io/v1
kind: ProviderConfig
metadata:
  name: storage-minio
  namespace: crossplane-system
spec:
  credentials:
    apiSecretRef:
      name: storage-minio
      namespace: minio-tenant
    source: InjectedIdentity
  minioURL: "http://myminio-hl.minio-tenant.svc.cluster.local:9000/"
kubectl apply -f minio-provider-config.yaml

That's it for provider-minio.

provider-kubernetes configuration

The second provider needed for storage-minio is provider-kubernetes. Since we want to observe Policies created by provider-minio, we need to create a ServiceAccount for provider-kubernetes that actually has permissions to observe these resources.

The following file creates a ServiceAccount, ClusterRole and ClusterRoleBinding for those permissions.

# rbac.yaml

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: storage-kubernetes
rules:
- apiGroups:
  - kubernetes.crossplane.io
  resources:
  - objects
  - objects/status
  - observedobjectcollections
  - observedobjectcollections/status
  - providerconfigs
  - providerconfigs/status
  - providerconfigusages
  - providerconfigusages/status
  verbs:
  - get
  - list
  - watch
  - update
  - patch
  - create
- apiGroups:
  - kubernetes.crossplane.io
  resources:
  - '*/finalizers'
  verbs:
  - update
- apiGroups:
  - coordination.k8s.io
  resources:
  - secrets
  - configmaps
  - events
  - leases
  verbs:
  - '*'
- apiGroups:
  - minio.crossplane.io
  resources:
  - policies
  verbs:
  - watch
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: storage-kubernetes
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: storage-kubernetes
subjects:
- kind: ServiceAccount
  name: storage-kubernetes
  namespace: crossplane-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: storage-kubernetes
  namespace: crossplane-system
kubectl apply -f rbac.yaml

Now we can update provider-kubernetes with a DeploymentRuntimeConfig to use this new ServiceAccount. Additionally, we provide the basic ProviderConfig needed by provider-kubernetes.

# kubernetes-provider-config.yaml

---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: crossplane-contrib-provider-kubernetes
spec:
  package: xpkg.crossplane.io/crossplane-contrib/provider-kubernetes:v0.18.0
  runtimeConfigRef:
    apiVersion: pkg.crossplane.io/v1beta1
    kind: DeploymentRuntimeConfig
    name: storage-kubernetes
---
apiVersion: pkg.crossplane.io/v1beta1
kind: DeploymentRuntimeConfig
metadata:
  name: storage-kubernetes
spec:
  serviceAccountTemplate:
    metadata:
      name: storage-kubernetes
---
apiVersion: kubernetes.crossplane.io/v1alpha1
kind: ProviderConfig
metadata:
  name: storage-kubernetes
spec:
  credentials:
    source: InjectedIdentity
kubectl apply -f kubernetes-provider-config.yaml

That's it for provider-kubernetes and the complete installation of storage-minio! Now we can finally create our first claim and see the configuration package in action!

Creating Buckets for Alice and Bob

Everything is up and running and we can create our first claim - or rather, our first claims! Let's assume that, by default, we need two buckets for every user of the platform. Therefore, we create two two buckets named alice and alice-shared for the user "Alice" and bob and bob-shared for the user "Bob".

# claims.yaml

---
apiVersion: pkg.internal/v1beta1
kind: Storage
metadata:
  name: alice
spec:
  owner: alice
  buckets:
    - bucketName: alice
    - bucketName: alice-shared
---
apiVersion: pkg.internal/v1beta1
kind: Storage
metadata:
  name: bob
spec:
  owner: bob
  buckets:
    - bucketName: bob
    - bucketName: bob-shared
kubectl apply -f claims.yaml

Requesting access to Buckets from Bob

Now that everyone has their buckets, Alice wants to have access to bob-shared since both are working on a project together and she needs access to his results. Since Alice also needs to upload her results to that bucket she needs ReadWrite access.

# claims.yaml

---
apiVersion: pkg.internal/v1beta1
kind: Storage
metadata:
  name: alice
spec:
  owner: alice
  buckets:
    - bucketName: alice
    - bucketName: alice-shared
  bucketAccessRequests:
    - bucketName: bob-shared
      permission: ReadWrite
---
apiVersion: pkg.internal/v1beta1
kind: Storage
metadata:
  name: bob
spec:
  owner: bob
  buckets:
    - bucketName: bob
    - bucketName: bob-shared
kubectl apply -f claims.yaml

Note that the status of the XStorage object alice-... has changed to READY: False since the alice.readwrite.bob-shared policy does not exist yet and, therefore, cannot be attached to the user role.

kubectl get xstorages

# Output
NAME          SYNCED   READY   COMPOSITION        AGE
alice-d7kbk   True     False   provider-storage   13m
bob-2s79f     True     True    provider-storage   13m
kubectl describe users.minio.crossplane.io alice

# Output
Name:         alice
...
Status:
  At Provider:
    Policies:   alice.owner.alice,alice.owner.alice-shared
    Status:     enabled
    User Name:  alice
...

Granting access to Buckets to Alice

Bob is the owner of bob-shared so he needs to grant Alice the ReadWrite permission to the bucket.

# claims.yaml

---
apiVersion: pkg.internal/v1beta1
kind: Storage
metadata:
  name: alice
spec:
  owner: alice
  buckets:
    - bucketName: alice
    - bucketName: alice-shared
  bucketAccessRequests:
    - bucketName: bob-shared
      permission: ReadWrite
---
apiVersion: pkg.internal/v1beta1
kind: Storage
metadata:
  name: bob
spec:
  owner: bob
  buckets:
    - bucketName: bob
    - bucketName: bob-shared
  bucketAccessGrants:
    - bucketName: bob-shared
      permission: ReadWrite
      grantees:
        - alice
kubectl apply -f claims.yaml

Note that it can take up to two minutes until the new policy is observed and synced. The status of the XStorage object has changed back to READY: True since the alice.readwrite.bob-shared policy has been created (Bob granted access to Alice) and is now attached to the user role.

kubectl get xstorages

# Output
NAME          SYNCED   READY   COMPOSITION        AGE
alice-d7kbk   True     True    storage-minio      15m
bob-2s79f     True     True    storage-minio      15m
kubectl describe users.minio.crossplane.io alice

# Output
Name:         alice
...
Status:
  At Provider:
    Policies:   alice.owner.alice,alice.owner.alice-shared,alice.readwrite.bob-shared
    Status:     enabled
    User Name:  alice
...

Conclusion

Congratulations! You have worked through the whole tutorial and have installed storage-minio and deployed your first claims. You should no be able to follow most of the How-to guides in the sidebar and look through the API definitions in the Reference guides and see what other options you can enable/disable in the claims.

We are always happy about feedback and suggestions on how to improve the documentation or provider-storage as a whole. Therefore, if you have trouble following the tutorial or find errors please open an issue on GitHub and let us know about it!