274 lines
9.6 KiB
Makefile
274 lines
9.6 KiB
Makefile
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 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 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 realm=${KEYCLOAK_REALM} client_id=${MINIO_OIDC_CLIENT_ID} \
|
|
redirect_url="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}"
|