Clients

S3 is available to external clients over s3, as well as a few supported operations over http REST (for convenience).

The mc client is recommended, as that gives you the most efficient experience. Also see the example go client that uses a dedicated MinIO client library.

The REST client should be used sparingly, as that creates a new STS session for every invocation.

mc Client

To use MinIO’s mc client, you will need to perform a token exchange with MinIO’s Security Token Service (STS). This creates a temporary STS session with your user credentials.

Diagram

The basic flow is, with your Data Fabric auth token:

  1. Get an STS session.

  2. Use the STS session access key, secret and token with your s3 client of choice.

The procedures listed below use the following to assist in extracting elements from service response payloads:

  • jq

  • yq

If you don’t have these, you can still run through the steps but you will need to extract the parts from the responses yourself.

Get an Auth Token

If you do not have one yet, get an auth token for yourself from Data Fabric with an audience for the df-minio keycloak client.

AUTH_TOKEN=$(curl -s -X GET \
  'http://localhost/api/v1/auth/token' \
  -H 'accept: application/json' \
  -H 'Keycloak-Client-ID: df-minio' \ (1)
  -H 'Authorization: Basic YWRtaW46eUNITHBDaG12dDRuTVUwNWpaZTZBbGl0' \ (2)
  | jq -r '.token') (3)
1 The keycloak client to include as an audience for the token.
2 Your username:password credentials, base64 encoded.
3 Grab the token attribute from the JSON response.

Open an STS Session

Using your AUTH_TOKEN, get an STS session credentials.

STS_CREDENTIALS=$(curl -s -X POST \
  http://s3.localhost?Action=AssumeRoleWithWebIdentity&Version=2011-06-15&WebIdentityToken=$AUTH_TOKEN \    (1)
  | yq --input-format xml '.AssumeRoleWithWebIdentityResponse.AssumeRoleWithWebIdentityResult.Credentials') (2)
1 Pass your Data Fabric auth token.
2 Extract the STS credentials from the xml response.

From the STS_CREDENTIALS, parse out the session access key, secret and token.

STS_ACCESS_KEY=$(echo -n $STS_CREDENTIALS | yq '.AccessKeyId')
STS_SECRET_KEY=$(echo -n $STS_CREDENTIALS | yq '.SecretAccessKey')
STS_SESSION_TOKEN=$(echo -n $STS_CREDENTIALS | yq '.SessionToken')

STS sessions are short-lived, and will expire after 15 minutes.

Configure mc

Export a MC_HOST_{alias} environment variable to configure the mc client, using your STS access key, secret and session token.

export MC_HOST_df=http://$STS_ACCESS_KEY:$STS_SECRET_KEY:$STS_SESSION_TOKEN@s3.localhost

Then use mc as you normally would.

mc ls df
Why STS?

STS session tokens are used to tie the session to a user in Keycloak. This is needed to ensure proper access controls (including classification markings) are in place for the user.

Without an STS token, clients will be restricted from accessing any object with a classification marking.

For more info, see the STS docs.

go Client

The go client for MinIO handles the STS token exchange for you, and will also renew the token if/when it expires.

To set up the client, you just pass it the URL to MinIO and your Data Fabric auth token.

The example go code below is a function you can drop into your go app for creating a minio.Client instance.

import (
	"fmt"
	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"github.com/rs/zerolog/log"
	"net/url"
)

// newMinioStsClient creates a new minio client with "STSWebIdentity" credentials.
// The `stsEndpoint` should be the URL to minio's REST API (ex: http://s3.localhost).
// The `authToken` should be the invoking user's base64 encoded JWT (note that this needs an audience with the `df-minio` client).
func newMinioStsClient(stsEndpoint, authToken string) (*minio.Client, error) {
	log.Debug().Msgf("STS endpoint: %s", stsEndpoint)

	var getWebTokenExpiry = func() (*credentials.WebIdentityToken, error) {
		return &credentials.WebIdentityToken{
			Token: authToken,
		}, nil
	}

	stsUrl, err := url.Parse(stsEndpoint)
	if err != nil {
		return nil, fmt.Errorf("Failed to parse STS Endpoint '%s':  %w", stsEndpoint, err)
	}

	sts, err := credentials.NewSTSWebIdentity(stsEndpoint, getWebTokenExpiry)
	if err != nil {
		return nil, fmt.Errorf("Could not get STS credentials from '%s':  %w", stsEndpoint, err)
	}

	opts := &minio.Options{
		Creds:        sts,
		BucketLookup: minio.BucketLookupAuto,
	}

	return minio.New(stsUrl.Host, opts)
}

Using the function above, create a minio client for a user’s session with their auth token.

mc, _ := newMinioStsClient("http://s3.localhost", token)

And retain it for the life of your user auth token session. The client will renew the STS session when needed.

buckets, _ := mc.ListBuckets(context.Background())

REST Client

The REST API is rooted at /api/v1/s3 and provides basic bucket and object operations suitable for simple workloads.

Diagram

Below are just a few basic examples using the REST API.

To explore the full API, download the OpenAPI or view it in the Swagger docs.

If you need deeper s3 protocol integration, see the mc or go client examples.

List Available Buckets

Request
curl -X 'GET' \
  'http://localhost/api/v1/s3/buckets' \
  -H 'accept: application/json' \
  -H 'Authorization: Basic YWRtaW46eUNITHBDaG12dDRuTVUwNWpaZTZBbGl0' (1)
1 Can use Basic (username/password) or Bearer token.
Response
[
  {
    "name": "df-backups",
    "creationDate": "2024-11-04T18:41:50.255Z"
  },
  {
    "name": "df-notebooks",
    "creationDate": "2024-11-04T18:41:51.321Z"
  },
  {
    "name": "df-schemas",
    "creationDate": "2024-11-04T18:41:56.739Z"
  },
  {
    "name": "inbox-public",
    "creationDate": "2024-11-04T18:42:00.742Z"
  }
]
Actual bucket listing will vary.

Upload a File

Request
curl -X 'PUT' \
  'http://localhost/api/v1/s3/buckets/inbox-public/objects/content?objectName=my-file.txt&classification=UNCLASSIFIED' \ (1)
  -H 'accept: application/json' \ (2)
  -H 'Authorization: Basic YWRtaW46eUNITHBDaG12dDRuTVUwNWpaZTZBbGl0' \ (3)
  -H 'Content-Type: application/json' \
  -d 'This is my file.' (4)
1 Uploading file my-file.txt to bucket inbox-public with marking UNCLASSIFIED.
2 The response will be a JSON payload describing the uploaded object.
3 Can use Basic (username/password) or Bearer token.
4 Raw content of file.
Response
{
  "name": "my-file.txt",
  "etag": "32ea80dfecd60916d9091b304dd4efb0-1",
  "sizeBytes": 16
}

List Objects in Bucket

Request
curl -X 'GET' \
  'http://localhost/api/v1/s3/buckets/inbox-public/objects' \ (1)
  -H 'accept: application/json' \
  -H 'Authorization: Basic YWRtaW46eUNITHBDaG12dDRuTVUwNWpaZTZBbGl0' (2)
1 List contents of bucket inbox-public.<2> The response will be a JSON payload describing the uploaded object.
2 Can use Basic (username/password) or Bearer token.
Response
[
  {
    "name": "my-file.txt",
    "tags": {},
    "etag": "32ea80dfecd60916d9091b304dd4efb0-1",
    "classification": {
      "raw": "U",
      "components": {
        "classification": "U",
        "disseminationControls": [],
        "ownerProducer": [
          "USA"
        ],
        "releasableTo": []
      }
    },
    "lastModified": "2024-11-04T22:05:18.561Z",
    "sizeBytes": 16
  }
]

Download a File

Request
curl -X 'GET' \
  'http://localhost/api/v1/s3/buckets/inbox-public/objects/content?objectName=my-file.txt' \ (1)
  -H 'accept: */*' \
  -H 'Authorization: Basic YWRtaW46eUNITHBDaG12dDRuTVUwNWpaZTZBbGl0' (2)
1 Downloading file my-file.txt from bucket inbox-public.
2 Can use Basic (username/password) or Bearer token.

The response will be an octet stream of the binary content of the file.

To explore the full API, download the OpenAPI or view it in the Swagger docs.