set fallback := true export MINIO_NAMESPACE := env("MINIO_NAMESPACE", "minio") export MINIO_CHART_VERSION := env("MINIO_CHART_VERSION", "5.4.0") export MINIO_OIDC_CLIENT_ID := env("MINIO_OIDC_CLIENT_ID", "minio") export MINIO_STORAGE_SIZE := env("MINIO_STORAGE_SIZE", "50Gi") export KEYCLOAK_REALM := env("KEYCLOAK_REALM", "buunstack") export K8S_VAULT_NAMESPACE := env("K8S_VAULT_NAMESPACE", "vault") export EXTERNAL_SECRETS_NAMESPACE := env("EXTERNAL_SECRETS_NAMESPACE", "external-secrets") [private] default: @just --list --unsorted --list-submodules # Add Helm repository add-helm-repo: # We use charts.min.io instead of operator.min.io because the operator does not support # standalone mode. # helm repo add minio https://operator.min.io/ helm repo add minio https://charts.min.io/ helm repo update # Remove Helm repository remove-helm-repo: helm repo remove minio # Create JupyterHub namespace create-namespace: kubectl get namespace ${MINIO_NAMESPACE} &>/dev/null || \ kubectl create namespace ${MINIO_NAMESPACE} # Delete MinIO namespace delete-namespace: kubectl delete namespace ${MINIO_NAMESPACE} --ignore-not-found # Create root credentials via External Secret or direct Secret create-root-credentials: #!/bin/bash set -euo pipefail if helm status external-secrets -n ${EXTERNAL_SECRETS_NAMESPACE} &>/dev/null; then echo "External Secrets Operator detected. Creating root credentials via ExternalSecret..." username="minioadmin" password=$(just utils::random-password) just vault::put-root minio/admin username="${username}" password="${password}" kubectl delete externalsecret minio -n ${MINIO_NAMESPACE} --ignore-not-found gomplate -f minio-root-external-secret.gomplate.yaml | kubectl apply -f - echo "Waiting for ExternalSecret to sync..." kubectl wait --for=condition=Ready externalsecret/minio \ -n ${MINIO_NAMESPACE} --timeout=60s else echo "External Secrets Operator not found. Creating root secret directly..." username="minioadmin" password=$(just utils::random-password) kubectl delete secret minio -n ${MINIO_NAMESPACE} --ignore-not-found kubectl create secret generic minio -n ${MINIO_NAMESPACE} \ --from-literal=rootUser="${username}" \ --from-literal=rootPassword="${password}" if helm status vault -n ${K8S_VAULT_NAMESPACE} &>/dev/null; then just vault::put-root minio/admin username="${username}" password="${password}" fi fi # Add Keycloak policy and mapper add-keycloak-minio-policy: #!/bin/bash set -euo pipefail POLICY_VALUE="${MINIO_POLICY:-readwrite}" echo "Setting MinIO policy attribute with default value: ${POLICY_VALUE}" just keycloak::add-attribute-mapper \ "${MINIO_OIDC_CLIENT_ID}" \ "minioPolicy" \ "MinIO Policy" \ "minioPolicy" \ "readwrite,readonly,writeonly" \ "${POLICY_VALUE}" \ "MinIO Policy" # Install MinIO install: #!/bin/bash set -euo pipefail export MINIO_HOST=${MINIO_HOST:-} if [ "${MINIO_HOST}" = "" ]; then MINIO_HOST=$( gum input --prompt="MinIO host (FQDN): " --width=100 \ --placeholder="e.g., minio.example.com" ) fi export MINIO_CONSOLE_HOST=${MINIO_CONSOLE_HOST:-} if [ "${MINIO_CONSOLE_HOST}" = "" ]; then MINIO_CONSOLE_HOST=$( gum input --prompt="MinIO Console host (FQDN): " --width=100 \ --placeholder="e.g., minio-console.example.com" ) fi just keycloak::create-client ${KEYCLOAK_REALM} ${MINIO_OIDC_CLIENT_ID} \ "https://${MINIO_HOST}/oauth_callback,https://${MINIO_CONSOLE_HOST}/oauth_callback" just add-keycloak-minio-policy just create-namespace just create-root-credentials just add-helm-repo gomplate -f minio-values.gomplate.yaml -o minio-values.yaml helm upgrade --install minio minio/minio \ --version ${MINIO_CHART_VERSION} -n ${MINIO_NAMESPACE} --create-namespace --wait \ -f minio-values.yaml # Uninstall MinIO uninstall: helm uninstall minio -n ${MINIO_NAMESPACE} --wait --ignore-not-found kubectl delete namespace ${MINIO_NAMESPACE} --ignore-not-found just keycloak::delete-client ${KEYCLOAK_REALM} ${MINIO_OIDC_CLIENT_ID} # List MinIO internal policies and users (for debugging) debug-info: @kubectl -n ${MINIO_NAMESPACE} exec -it deploy/minio -- \ bash -c "mc alias set local http://localhost:9000 $(just root-username) $(just root-password) && \ echo '--- Policies ---' && \ mc admin policy list local && \ echo '--- Users ---' && \ mc admin user list local" # Print MinIO root user root-username: @kubectl -n ${MINIO_NAMESPACE} get secret minio -o jsonpath='{.data.rootUser}' | base64 -d @echo # Print MinIO root password root-password: @kubectl -n ${MINIO_NAMESPACE} get secret minio -o jsonpath='{.data.rootPassword}' | base64 -d @echo # Create a bucket create-bucket bucket='': #!/bin/bash set -euo pipefail ROOT_USER=$(just root-username) ROOT_PASSWORD=$(just root-password) bucket={{ bucket }} while [ -z "${bucket}" ]; do bucket=$( gum input --prompt="Bucket name: " --width=100 \ --placeholder="e.g., my-bucket" ) done kubectl -n ${MINIO_NAMESPACE} exec -it deploy/minio -- \ bash -c "mc alias set local http://localhost:9000 ${ROOT_USER} ${ROOT_PASSWORD} && \ mc mb --ignore-existing local/${bucket}" # Check if a bucket exists (returns exit code 0 if exists, 1 if not) [no-exit-message] bucket-exists bucket: #!/bin/bash set -euo pipefail ROOT_USER=$(just root-username) ROOT_PASSWORD=$(just root-password) if kubectl -n ${MINIO_NAMESPACE} exec -it deploy/minio -- \ bash -c "mc alias set local http://localhost:9000 ${ROOT_USER} ${ROOT_PASSWORD} >/dev/null 2>&1 && \ mc ls local/{{ bucket }} >/dev/null 2>&1"; then exit 0 # Bucket exists else exit 1 # Bucket does not exist fi # Create MinIO user create-user user='' bucket='': #!/bin/bash set -euo pipefail USER="{{ user }}" BUCKET="{{ bucket }}" while [ -z "${USER}" ]; do USER=$(gum input --prompt="Username: " --width=100 --placeholder="e.g., airbyte") done if [ -z "${BUCKET}" ]; then BUCKET="${USER}-storage" fi echo "Creating MinIO user and bucket for ${USER}..." # Generate credentials ACCESS_KEY="${USER}" SECRET_KEY=$(just utils::random-password) # Get root credentials ROOT_USER=$(just root-username) ROOT_PASSWORD=$(just root-password) # Create bucket and user using mc (via existing MinIO pod) echo "Setting up mc alias..." kubectl -n ${MINIO_NAMESPACE} exec deploy/minio -- \ mc alias set local http://localhost:9000 ${ROOT_USER} ${ROOT_PASSWORD} echo "Creating bucket..." kubectl -n ${MINIO_NAMESPACE} exec deploy/minio -- \ mc mb local/${BUCKET} --ignore-existing echo "Creating user..." kubectl -n ${MINIO_NAMESPACE} exec deploy/minio -- \ mc admin user add local ${ACCESS_KEY} ${SECRET_KEY} echo "Attaching policy..." kubectl -n ${MINIO_NAMESPACE} exec deploy/minio -- \ mc admin policy attach local readwrite --user=${ACCESS_KEY} echo "Setting bucket policy..." kubectl -n ${MINIO_NAMESPACE} exec deploy/minio -- \ mc anonymous set none local/${BUCKET} # Store credentials in Vault if available if helm status external-secrets -n ${EXTERNAL_SECRETS_NAMESPACE} &>/dev/null; then echo "Storing credentials in Vault..." just vault::put ${USER}/minio \ access_key="${ACCESS_KEY}" \ secret_key="${SECRET_KEY}" \ bucket="${BUCKET}" \ endpoint="http://minio.${MINIO_NAMESPACE}.svc.cluster.local:9000" echo "Credentials stored in Vault at: ${USER}/minio" else echo "MinIO credentials for ${USER}:" echo " Access Key: ${ACCESS_KEY}" echo " Secret Key: ${SECRET_KEY}" echo " Bucket: ${BUCKET}" echo " Endpoint: http://minio.${MINIO_NAMESPACE}.svc.cluster.local:9000" fi echo "✅ MinIO user and bucket created for ${USER}" # Get MinIO credentials from Vault get-user-credentials user='': #!/bin/bash set -euo pipefail USER="{{ user }}" while [ -z "${USER}" ]; do USER=$(gum input --prompt="Username: " --width=100 --placeholder="e.g., airbyte") done if helm status external-secrets -n ${EXTERNAL_SECRETS_NAMESPACE} &>/dev/null; then echo "Getting MinIO credentials for ${USER} from Vault..." just vault::get ${USER}/minio else echo "External Secrets not available. Please check the credentials manually." exit 1 fi # Grant policy to user for specific operations grant-policy user='' policy='readwrite': #!/bin/bash set -euo pipefail USER="{{ user }}" POLICY="{{ policy }}" while [ -z "${USER}" ]; do USER=$(gum input --prompt="Username: " --width=100 --placeholder="e.g., dagster") done echo "Granting ${POLICY} policy to user ${USER}..." ROOT_USER=$(just root-username) ROOT_PASSWORD=$(just root-password) # Get the MinIO pod name dynamically MINIO_POD=$(kubectl get pods -n ${MINIO_NAMESPACE} -l app.kubernetes.io/name=minio -o jsonpath='{.items[0].metadata.name}') kubectl -n ${MINIO_NAMESPACE} exec ${MINIO_POD} -- \ bash -c "mc alias set local http://localhost:9000 ${ROOT_USER} ${ROOT_PASSWORD} && \ mc admin policy attach local ${POLICY} --user=${USER}" echo "✅ Policy ${POLICY} granted to user ${USER}"