Skip to content

Management SDKs

Go and Python clients for IOLake's management API: everything under /_admin/*, plus STS.

install source
Go go get github.com/io-lake/iolake-go-sdk iolake-go-sdk
Python pip install iolake-sdk (import iolake) iolake-python-sdk

Both are developed in the main repository under sdk/ and mirrored to their own repos on every merge. Both are standard library only: no dependencies to vendor into an operator or a CSI driver. Method names match: Go CreatePolicy is Python create_policy.

They don't do S3 data operations. Use the S3 SDK you already have (boto3, aws-sdk-go-v2, rclone, mountpoint-s3), pointed at the same endpoint with a credential these mint or obtain.

What they cover

  • Tenants and tenant admins.
  • Users and access keys, including suspend and reactivate, and keys confined to a bucket or prefix.
  • IAM policies, groups and roles, attached to users, groups or roles.
  • Identity providers: the operator's and each tenant's own OIDC provider.
  • STS: AssumeRoleWithWebIdentity from a client that needs no keys.
  • Block Public Access at bucket, tenant and cluster level, and a bucket's policy status.
  • Buckets, bucket policies and dedup.
  • One-call provisioning: a bucket plus a key confined to it, with rotation and teardown.
  • Cluster operations: pools, nodes, OSD state, rebalance, usage, metrics.
  • KMS keys, Iceberg warehouses, and cluster config.

The concepts are explained in Identity and Access and Public Access.

Configure

from iolake import Client
admin = Client.from_env()          # IOLAKE_ENDPOINT, IOLAKE_ACCESS_KEY(_FILE), IOLAKE_SECRET_KEY(_FILE)
admin, err := iolake.NewFromEnv()

The AWS variable names (AWS_ACCESS_KEY_ID, …) work as fallbacks. In Kubernetes, prefer the _FILE forms with a mounted Secret. The credential must be unscoped: a key confined to a bucket is refused on the management API.

Examples

A tenant with its own identity provider, and a role its CI assumes with no stored credential:

from iolake import Client, tenant_oidc_provider_name

acme = Client.from_env()           # acme's tenant admin
acme.put_oidc_provider(tenant_oidc_provider_name("acme"), {
    "issuer_url": "https://keycloak.acme.example/realms/acme",
    "client_id": "iolake", "claim_name": "groups"})
acme.create_policy("data-rw", {"Version": "2012-10-17", "Statement": [{
    "Effect": "Allow", "Action": "s3:*",
    "Resource": ["arn:aws:s3:::acme-data", "arn:aws:s3:::acme-data/*"]}]})
role = acme.create_role("ci", trust_policy)          # see Identity and Access
acme.attach_policy("data-rw", role_name="ci")

# In CI
creds = Client(endpoint=E).assume_role_with_web_identity(role.arn, token, "build-42")
s3 = boto3.client("s3", **creds.boto3_kwargs(E))

Suspend someone now, decide later:

_, err := admin.SuspendUser(ctx, userID)      // every key refused; nothing deleted
_, err = admin.ActivateUser(ctx, userID)

A bucket and a key confined to it, for an app:

ba = admin.provision_bucket("app-1", provisioner_user_id=prov_id)
s3 = boto3.client("s3", **ba.boto3_kwargs(E))

Block public access for a whole tenant:

_, err := acme.PutPublicAccessBlock(ctx, "", iolake.BlockAll, nil)

Errors

Both surface the HTTP status and, for S3 and STS errors, the error code (AccessDenied, NoSuchBucket, InvalidIdentityToken, …). Use them to make calls idempotent:

try:
    admin.create_bucket("app-1")
except APIError as e:
    if not e.already_exists:
        raise
if err := admin.CreateBucket(ctx, "app-1", ""); err != nil && !iolake.IsAlreadyExists(err) {
    return err
}

The full reference, with every method, is in each SDK's README.