Backblaze B2 Operator for Kubernetes
Table of Contents
As you might guess by some of my older entries, I’m a fan of Backblaze B2 object storage.
Some time ago I created my first Kubernetes operator using Operator-SDK in Golang. Before that, I had some experience with python pykube/kopf, but these libraries are pretty much abandoned, so I decided to take a look at the “first party” solution.
I wanted to create Backblaze B2 buckets and keys in the cluster, but I noticed that at the time, there weren’t any operators available, so I created my own. It supports creating buckets and keys with ACL. I know - what a diversity of feature from a storage operator
The operator is open-source and can be found on github.com/mgruszkiewicz/backblaze-operator
How to setup?⌗
Setup should be relatively straightforward, you need:
- create application key in your b2 account with correct permissions or use master application key
- helm
Creating keys⌗
Creating application keys with specific capabilities/permissions is a bit tricky on Backblaze B2, as it is not possible from the web interface - you need to use the B2 CLI to do that.
First, you need to install the b2 cli, that will depend on the platform you are using. Refer to the official Backblaze documentation on how to do that
then authenticate to your account
b2 account authorize
and finally, we can create a key for operator
b2 key create operator-blog writeKeys,deleteKeys,listBuckets,listAllBucketNames,readBuckets,writeBuckets,deleteBuckets
The output will contain two values, separated by space - the first one will be the application id, the second application key
Setup operator using Helm⌗
helm upgrade --install backblaze-operator backblaze-operator \
--set credentials.b2ApplicationId="your-application-id" \
--set credentials.b2ApplicationKey="your-application-key" \
--set credentials.b2Region="us-west-004" \
--namespace backblaze-operator --create-namespace \
--repo https://mgruszkiewicz.github.io/helm-charts
Setup operator in FluxCD repository⌗
If you are using GitOps (and you probably should!) to manage your cluster, you can also easily install the operator using FluxCD HelmReleases. As we will need to pass the Backblaze keys, you will need a way to pass securely the keys to the cluster. In my case I prefer to store the secrets in Vault, and I passed them out to cluster via ExternalSecrets, but the method doesn’t matter - you can use variable substitution or create a secret manually and reference it in values.
First, create the secret with your Backblaze credentials:
kubectl create secret generic backblaze-credentials \
--from-literal=B2_APPLICATION_ID="your-application-id" \
--from-literal=B2_APPLICATION_KEY="your-application-key"
--from-literal=B2_REGION="your-b2-region" \
--namespace backblaze-operator
Then apply the following FluxCD configuration:
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: isseispace
namespace: flux-system
spec:
interval: 1h
url: https://mgruszkiewicz.github.io/helm-charts
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: backblaze-operator
namespace: backblaze-operator
spec:
interval: 5m
chart:
spec:
chart: backblaze-operator
sourceRef:
kind: HelmRepository
name: isseispace
namespace: flux-system
values:
credentials:
secret:
useSecret: true
name: backblaze-credential
Creating an example bucket⌗
After a successful operator installation, we can try to create a new Backblaze B2 bucket from our Kubernetes cluster using CRD.
apiVersion: b2.issei.space/v1alpha2
kind: Bucket
metadata:
name: my-b2-bucket
spec:
atProvider:
acl: private
The metadata.name will be used as a bucket name.
Note - to create a bucket with acl: public, you first need to add a payment method to your Backblaze account, otherwise the creation process will fail.
Let’s check the status:
❯ kubectl describe buckets.b2.issei.space my-b2-bucket
Name: my-b2-bucket
Namespace: default
Labels: <none>
Annotations: <none>
API Version: b2.issei.space/v1alpha2
Kind: Bucket
Metadata:
Creation Timestamp: 2025-12-27T15:55:11Z
Finalizers:
bucket.b2.issei.space/finalizer
Generation: 1
Resource Version: 762
UID: 3ed908df-373a-452a-825c-b6215ec9d2a0
Spec:
At Provider:
Acl: private
Status:
At Provider:
Acl: private
Reconciled: true
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal BucketCreated 2m42s bucket-controller Successfully created bucket my-b2-bucket with ACL private
Now let’s create a new application key that has only access to our new bucket
apiVersion: b2.issei.space/v1alpha2
kind: Key
metadata:
name: my-b2-key
spec:
atProvider:
bucketName: my-b2-bucket
capabilities:
- deleteFiles
- listAllBucketNames
- listBuckets
- listFiles
- readBucketEncryption
- readBucketReplications
- readBuckets
- readFiles
- shareFiles
- writeBucketEncryption
- writeBucketReplications
- writeFiles
writeConnectionSecretToRef:
name: new-key
and let’s check the status:
❯ kubectl describe secret new-key
Name: new-key
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
AWS_ACCESS_KEY_ID: 25 bytes
AWS_SECRET_ACCESS_KEY: 31 bytes
bucketName: 21 bytes
endpoint: 30 bytes
keyName: 9 bytes
Now you can connect your application to new Backblaze B2 object storage bucket!
For compatibility with apps that expect S3 object storage, the secret is created with AWS S3 named keys.